home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / os2 / os2smpl.txt < prev    next >
Encoding:
Text File  |  2013-11-08  |  2.9 MB  |  90,571 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1.  OS/2 v1.2 Sample Code
  2.  
  3.  
  4.  ACCEL.C
  5.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\ACCEL\ACCEL.C
  6.  
  7.  /*
  8.   *  ACCEL.C -- Sample demonstrating calls included with INCL_WINACCELERATORS
  9.   *
  10.   *  Overview:
  11.   *        Accelerators are used to reduce the number of keystrokes needed to
  12.   *  execute a command (hence "accelerating" a user's processing time)
  13.   *
  14.   *  Strategy:
  15.   *        This application allows the user to experiment with various setting
  16.   *  by popping up a dialog box in which the user can specify an accelerator.
  17.   *  One possible modification to this program is to have the user hit the
  18.   *  desired key sequence, and to use KbdCharIn() to figure out what the key
  19.   *  sequence is, and then set the accelerator.  Another is to implement the
  20.   *  "Delete" operation, by perhaps listing the accelerators in a list box.
  21.   *  This wasn't done primarily because that would require reorganization
  22.   *  (compression) of the accelerator table:  it could not be easily done with
  23.   *  a WinDeleteAccel call (because such a call does not exist).
  24.   */
  25.  #define INCL_WINACCELERATORS
  26.  #define        INCL_WINBUTTONS                        // Needed for checkboxe
  27.  #define        INCL_WINDIALOGS
  28.  #define        INCL_WINMESSAGEMGR
  29.  #define        INCL_WINFRAMEMGR                // for SC_MINIMIZE constant
  30.  #define INCL_WINWINDOWMGR
  31.  #include <os2.h>
  32.  
  33.  #include <malloc.h>                        // Needed for dynamic memory alloc
  34.  #include <stdio.h>                        // Needed for sscanf() call
  35.  #include "accel.h"                        // Needed for resource IDs
  36.  /*
  37.   * Globals
  38.   */
  39.  char        ach[8];                         // Temporary:  used to store Key:
  40.  char        szAppName[]        = "ACCEL.EXE";
  41.  char        szClassName[]        = "Accelerator";
  42.  char        szMessage[]        = " - Accelerator Table Example";
  43.  int        cbSize;                         // Size of Accel. Table in bytes
  44.  int        iTemp;                                // Used to store Key: value,
  45.  void        *pTemp;                         // Used so free() won't give warn
  46.  HAB        hab;
  47.  HACCEL        haccSystem;                        // Handle to system accelera
  48.  HACCEL        haccTable;                        // Handle to app-local accelt
  49.  HMQ     hmqAccel;
  50.  HWND        hwndAccel;                        // Client window
  51.  HWND        hwndAccelFrame;                 // Frame window
  52.  PACCELTABLE        pacctTable;                // Points to table with ACCEL e
  53.  /*
  54.      Macros
  55.  */
  56.  #define Message(s) WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, s, \
  57.                          szAppName, 0, MB_OK | MB_ICONEXCLAMATION)
  58.  #define        Check(b)   WinSendDlgItemMsg(hwndDlg, b, \
  59.                          BM_SETCHECK, MPFROMSHORT(1), 0L)
  60.  #define Checked(b) WinSendDlgItemMsg(hwndDlg, b, BM_QUERYCHECK, 0L, 0L)
  61.  /*
  62.      Internals
  63.  */
  64.  BOOL InitializeAccelTable(void);
  65.  /*
  66.   * Main routine...initializes window and message queue
  67.   */
  68.  void cdecl main(void) {
  69.      QMSG qmsg;
  70.      ULONG ctldata;
  71.  
  72.      /* Initialize a PM application */
  73.      hab = WinInitialize(0);
  74.      hmqAccel = WinCreateMsgQueue(hab, 0);
  75.  
  76.      /* Register the main window's class */
  77.      if (!WinRegisterClass(hab, szClassName, AccelWndProc, CS_SIZEREDRAW, 0))
  78.          return;
  79.      /*
  80.          Create the window
  81.          We create it without an accelerator table, but we'll load one later
  82.      */
  83.      ctldata = FCF_STANDARD & ~FCF_ACCELTABLE;
  84.      hwndAccelFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &ctldata,
  85.          szClassName, szMessage, WS_VISIBLE, (HMODULE) NULL, IDR_ACCEL, &hwndA
  86.      WinShowWindow(hwndAccelFrame, TRUE);
  87.      /*
  88.          Load the accelerator tables
  89.      */
  90.      if (!InitializeAccelTable()) {
  91.          Message("Accelerator table not initialized!");
  92.          return;
  93.      }
  94.  
  95.      /* Poll messages from event queue */
  96.      while(WinGetMsg(hab, (PQMSG)&qmsg, (HWND)NULL, 0, 0))
  97.          WinDispatchMsg(hab, (PQMSG)&qmsg);
  98.  
  99.      /* Clean up */
  100.      if (!WinDestroyAccelTable(haccTable))
  101.          Message("Could not destroy ACCELTABLE");
  102.      WinDestroyWindow(hwndAccelFrame);
  103.      WinDestroyMsgQueue(hmqAccel);
  104.      WinTerminate(hab);
  105.  }
  106.  
  107.  MRESULT CALLBACK AccelWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  108.  /*
  109.   * This routine processes WM_PAINT.  It passes
  110.   * everything else to the Default Window Procedure.
  111.   */
  112.      HPS                hPS;
  113.      RECTL        rcl;
  114.  
  115.      switch (msg) {
  116.  
  117.          case WM_HELP:
  118.              /* If WM_HELP, pop up Help dialog box */
  119.              WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, (HMODULE) NULL, IDD_H
  120.              break;
  121.  
  122.          case WM_COMMAND:
  123.              switch (COMMANDMSG(&msg)->cmd) {
  124.  
  125.                  /* On most WM_COMMAND messages, give the About... box */
  126.                  case IDM_ABOUT:
  127.                      WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc,
  128.                                (HMODULE) NULL, IDD_ABOUT, NULL);
  129.                      break;
  130.  
  131.                  /* Create your own accelerator dialog */
  132.                  case IDM_CREATE:
  133.                      WinDlgBox(HWND_DESKTOP, hwnd, CreateDlgProc,
  134.                                (HMODULE) NULL, IDD_CREATE, NULL);
  135.  
  136.                  default: break;
  137.              }
  138.              break;
  139.  
  140.          case WM_PAINT:
  141.              /* Open the presentation space */
  142.              hPS = WinBeginPaint(hwnd, NULL, &rcl);
  143.  
  144.              /* Fill the background with Dark Blue */
  145.              WinFillRect(hPS, &rcl, CLR_DARKBLUE);
  146.  
  147.              /* Finish painting */
  148.              WinEndPaint(hPS);
  149.              break;
  150.  
  151.          default: return WinDefWindowProc(hwnd, msg, mp1, mp2); break;
  152.      }
  153.      return 0L;
  154.  }
  155.  
  156.  MRESULT CALLBACK AboutDlgProc(hwndDlg, msg, mp1, mp2)
  157.  /*
  158.      About... dialog procedure
  159.  */
  160.  HWND hwndDlg;
  161.  USHORT msg;
  162.  MPARAM mp1;
  163.  MPARAM mp2;
  164.  {
  165.      switch(msg) {
  166.          case WM_COMMAND:
  167.              switch(COMMANDMSG(&msg)->cmd) {
  168.                  case DID_OK: WinDismissDlg(hwndDlg, TRUE);
  169.                  default: break;
  170.              }
  171.          default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  172.      }
  173.      return FALSE;
  174.  }
  175.  
  176.  MRESULT CALLBACK CreateDlgProc(hwndDlg, msg, mp1, mp2)
  177.  /*
  178.      Create Accelerator dialog procedure
  179.  */
  180.  HWND hwndDlg;
  181.  USHORT msg;
  182.  MPARAM mp1;
  183.  MPARAM mp2;
  184.  {
  185.      switch(msg) {
  186.          case WM_INITDLG:
  187.              /* Set the defaults */
  188.              Check(IDD_CHAR); Check(IDD_CMD);
  189.              break;
  190.  
  191.          case WM_COMMAND:
  192.              switch(COMMANDMSG(&msg)->cmd) {
  193.                  case DID_OK:
  194.                      /* Get the accelerator table (allocate an extra space) */
  195.                      cbSize = WinCopyAccelTable(haccTable, NULL, 0);
  196.                      pTemp = (void *) malloc(cbSize + sizeof(ACCEL));
  197.                      pacctTable = (PACCELTABLE) pTemp;
  198.                      cbSize = WinCopyAccelTable(haccTable, pacctTable, cbSize)
  199.  
  200.  #define accNew        pacctTable->aaccel[pacctTable->cAccel]
  201.  
  202.                      /*
  203.                          Command:
  204.                              if SYSCOMMAND, make the window minimize.
  205.                              if HELP, we'll pop up a dialog box.
  206.                              otherwise, pop up the About... dialog box.
  207.                      */
  208.                      if (Checked(IDD_SYSCMD)) accNew.cmd = SC_MINIMIZE;
  209.                      else accNew.cmd = IDM_ABOUT;
  210.  
  211.                      /* Get the states from the dialog box */
  212.                      accNew.fs = 0;
  213.                      if (Checked(IDD_ALT))        accNew.fs |= AF_ALT;
  214.                      if (Checked(IDD_CHAR))        accNew.fs |= AF_CHAR;
  215.                      if (Checked(IDD_CONTROL))        accNew.fs |= AF_CONTROL;
  216.                      if (Checked(IDD_FHELP))        accNew.fs |= AF_HELP;
  217.                      if (Checked(IDD_LONEKEY))        accNew.fs |= AF_LONEKEY;
  218.                      if (Checked(IDD_SCANCODE))        accNew.fs |= AF_SCANCOD
  219.                      if (Checked(IDD_SHIFT))        accNew.fs |= AF_SHIFT;
  220.                      if (Checked(IDD_SYSCMD))        accNew.fs |= AF_SYSCOMMAN
  221.                      if (Checked(IDD_VKEY))        accNew.fs |= AF_VIRTUALKEY;
  222.  
  223.                      /* Get the key to be defined */
  224.                      WinQueryDlgItemText(hwndDlg, IDD_ENTRY, 8, ach);
  225.                      if (('0' <= ach[0]) && (ach[0] <= '9')) {
  226.                          sscanf(ach, "%i", &iTemp);
  227.                          accNew.key = (USHORT) iTemp;
  228.                      }
  229.                      else accNew.key = (USHORT) ach[0];
  230.  
  231.                      /* Increment the count of accelerator records */
  232.                      pacctTable->cAccel++;
  233.  
  234.                      /* Cleanup, then create a new accelerator table */
  235.                      WinDestroyAccelTable(haccTable);
  236.                      haccTable = WinCreateAccelTable(hab, pacctTable);
  237.  
  238.                      /* Set the new accelerator table, and clean up */
  239.                      WinSetAccelTable(hab, haccTable, hwndAccelFrame);
  240.                      free(pTemp);
  241.  
  242.                  case DID_CANCEL:
  243.                      WinDismissDlg(hwndDlg, TRUE);
  244.  
  245.                  default: break;
  246.              }
  247.          default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  248.      }
  249.      return FALSE;
  250.  }
  251.  
  252.  BOOL InitializeAccelTable(void) {
  253.      /*
  254.          Initialize the accelerator table by loading it from the
  255.          resource file.        Note that you can load an accelerator
  256.          table from a DLL, if you change the NULL parameter.
  257.          The system accelerator table is accessible after this
  258.          call:  one possible use for this would be a List...
  259.          dialog box, which would list all system & app. accelerators.
  260.      */
  261.      haccSystem = WinQueryAccelTable(hab, NULL);
  262.      haccTable = WinLoadAccelTable(hab, 0, IDR_ACCEL);
  263.      return WinSetAccelTable(hab, haccTable, hwndAccelFrame);
  264.  }
  265.  
  266.  
  267.  APP.C
  268.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\MDI\APP.C
  269.  
  270.  /***************************************************************************\
  271.  * app.c - MDI Sample application
  272.  *
  273.  * Created by Microsoft Corporation, 1989
  274.  *
  275.  \***************************************************************************/
  276.  
  277.  #define INCL_WINSYS
  278.  #define INCL_WINCOMMON
  279.  #define INCL_WINMESSAGEMGR
  280.  #define INCL_WINPOINTERS
  281.  #define INCL_WININPUT
  282.  #define INCL_WINMENUS
  283.  #define INCL_WINFRAMEMGR
  284.  #define INCL_WINWINDOWMGR
  285.  #define INCL_WINRECTANGLES
  286.  #define INCL_WINHEAP
  287.  #define INCL_WINSCROLLBARS
  288.  #define INCL_GPIPRIMITIVES
  289.  
  290.  #include <os2.h>
  291.  #include "app.h"
  292.  #include "appdata.h"
  293.  #include "mdi.h"
  294.  #include "mdidata.h"
  295.  
  296.  
  297.  /*
  298.      Function prototypes
  299.  */
  300.  BOOL AppInit(VOID);
  301.  BOOL MDIInit(VOID);
  302.  VOID AppTerminate(VOID);
  303.  VOID MDITerminate(VOID);
  304.  BOOL AppNewDocument(USHORT, PSZ);
  305.  VOID TrackSplitbars(HWND, USHORT, SHORT, SHORT);
  306.  VOID MDIDesktopSize(HWND, MPARAM, MPARAM);
  307.  VOID MDIDesktopSetFocus(HWND, MPARAM);
  308.  VOID MDIDesktopActivateDoc(SHORT idMenuitem);
  309.  BOOL AppNewDocument(USHORT, PSZ);
  310.  NPDOC MDINewDocument(USHORT fsStyle, PSZ pszClassName);
  311.  VOID MDISetInitialDocPos(HWND hwndNewFrame);
  312.  
  313.  VOID AddToWindowMenu(NPDOC);
  314.  
  315.  
  316.  
  317.  int cdecl main(void)
  318.  {
  319.      QMSG qmsg;
  320.      /*
  321.       * Initialize the application globals
  322.       * and create the main window.
  323.       */
  324.      if (AppInit() == FALSE) {
  325.          WinAlarm(HWND_DESKTOP, WA_ERROR);
  326.          return(0);
  327.      }
  328.  
  329.      /*
  330.       * Initialize the MDI globals etc..
  331.       */
  332.      if (MDIInit() == FALSE) {
  333.          WinAlarm(HWND_DESKTOP, WA_ERROR);
  334.          WinAlarm(HWND_DESKTOP, WA_ERROR);
  335.          return(0);
  336.      }
  337.  
  338.      /*
  339.       * Create an initial, untitled document.
  340.       */
  341.      AppNewDocument(DS_HORZSPLITBAR | DS_VERTSPLITBAR, szDocClass);
  342.  
  343.      while (WinGetMsg(NULL, (PQMSG)&qmsg, NULL, 0, 0)) {
  344.          WinDispatchMsg(NULL, (PQMSG)&qmsg);
  345.      }
  346.  
  347.      /*
  348.       * Do the clean-up of the MDI code.
  349.       */
  350.      MDITerminate();
  351.  
  352.      /*
  353.       * Do the clean-up of the Application.
  354.       */
  355.      AppTerminate();
  356.  
  357.      DosExit(EXIT_PROCESS, 0);
  358.  }
  359.  
  360.  
  361.  MRESULT EXPENTRY MDIWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  362.  {
  363.      HPS hps;
  364.      RECTL rclPaint, rclWindow;
  365.      POINTL ptlPatternRef;
  366.  
  367.      switch (msg) {
  368.  
  369.      case WM_PAINT:
  370.          hps = WinBeginPaint(hwnd, (HPS)NULL, &rclPaint);
  371.  
  372.          /*
  373.           * Set the pattern to be at the top-left
  374.           * since we're top-left aligning the bits.
  375.           */
  376.          WinQueryWindowRect(hwnd, (PRECTL)&rclWindow);
  377.          ptlPatternRef.x = rclWindow.xLeft;
  378.          ptlPatternRef.y = rclWindow.yTop;
  379.          GpiSetPatternRefPoint(hps, &ptlPatternRef);
  380.  
  381.          WinFillRect(hps, &rclPaint, SYSCLR_APPWORKSPACE);
  382.  
  383.          WinEndPaint(hps);
  384.          break;
  385.  
  386.  #if 0
  387.      case WM_SIZE:
  388.  
  389.          /* HACK -- only reposition the windows if it is not going to or comin
  390.          from a minimized position, it would be better to what
  391.          WM_WINDOWPOSCHANGED and pay attention to the fs fields of the SWP
  392.          structure */
  393.  
  394.          if ( SHORT1FROMMP(mp1) && SHORT2FROMMP(mp1) &&
  395.               SHORT1FROMMP(mp2) && SHORT2FROMMP(mp2) ) {
  396.              MDIDesktopSize ( hwnd, mp1, mp2 );
  397.          }
  398.      break;
  399.  
  400.  #else
  401.      case WM_SIZE:
  402.          MDIDesktopSize ( hwnd, mp1, mp2 );
  403.          break;
  404.  #endif
  405.  
  406.      case WM_SETFOCUS:
  407.          MDIDesktopSetFocus(hwnd, mp2);
  408.          break;
  409.  
  410.      case WM_COMMAND:
  411.          switch (SHORT1FROMMP(mp1)) {
  412.  
  413.          /*
  414.           * Pass these accelerators onto the active document's
  415.           * frame so it can process it.
  416.           *
  417.           * These are the CMD_ values from the document system
  418.           * menu.
  419.           */
  420.          case CMD_DOCRESTORE:
  421.              WinSendMsg(hwndActiveDoc, WM_SYSCOMMAND, (MPARAM)SC_RESTORE, mp2)
  422.              break;
  423.  
  424.          case CMD_DOCNEXT:
  425.              WinSendMsg(hwndActiveDoc, WM_SYSCOMMAND, (MPARAM)SC_NEXT, mp2);
  426.              break;
  427.  
  428.          case CMD_DOCMINIMIZE:
  429.              WinSendMsg(hwndActiveDoc, WM_SYSCOMMAND, (MPARAM)SC_MINIMIZE, mp2
  430.              break;
  431.  
  432.          case CMD_DOCCLOSE:
  433.              WinSendMsg(hwndActiveDoc, WM_SYSCOMMAND, (MPARAM)SC_CLOSE, mp2);
  434.              break;
  435.  
  436.          case CMD_DOCSPLIT:
  437.              /*
  438.               * Call TrackSplitbars() with -1 for xMouse to tell
  439.               * it to reposition the pointer to where the
  440.               * splitbars currently are.
  441.               */
  442.              WinSetPointer(HWND_DESKTOP, hptrHVSplit);
  443.              TrackSplitbars(WinWindowFromID(hwndActiveDoc, FID_CLIENT),
  444.                      SPS_VERT | SPS_HORZ, -1, -1);
  445.              WinSetPointer(HWND_DESKTOP, hptrArrow);
  446.              break;
  447.  
  448.          case CMD_NEW:
  449.              if (AppNewDocument(DS_HORZSPLITBAR | DS_VERTSPLITBAR, szDocClass)
  450.                  WinAlarm(HWND_DESKTOP, WA_ERROR);
  451.              break;
  452.  
  453.          case CMD_CLOSE:
  454.              /*
  455.               * Close the active document.
  456.               */
  457.              if (hwndActiveDoc)
  458.                  WinSendMsg(hwndActiveDoc, WM_CLOSE, 0L, 0L);
  459.              break;
  460.  
  461.          case CMD_ABOUT:
  462.              /*
  463.               * Put up the About... dialog box
  464.               */
  465.              WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, NULL, IDD_ABOUT, NULL
  466.              break;
  467.  
  468.          case CMD_EXIT:
  469.              WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  470.              break;
  471.  
  472.          case CMD_ARRANGETILED:
  473.              ArrangeWindows(AWP_TILED);
  474.              break;
  475.  
  476.          case CMD_ARRANGECASCADED:
  477.              ArrangeWindows(AWP_CASCADED);
  478.              break;
  479.  
  480.          default:
  481.              /*
  482.               * The means a window title was selected from
  483.               * the window menu.  Have the MDI code activate
  484.               * the correct window based on the menuitem ID.
  485.               *
  486.               * WARNING: Be sure to keep you applications
  487.               * menuitem IDs < CMD_WINDOWITEMS.
  488.               */
  489.  
  490.              /* MULTIPLEMENU */
  491.              /*  Also in here we need to pass document unique WM_COMMAND
  492.                  messages on down to the document's client procs */
  493.  
  494.              if (SHORT1FROMMP(mp1) >= CMD_WINDOWITEMS)
  495.                  MDIDesktopActivateDoc(SHORT1FROMMP(mp1));
  496.              break;
  497.          }
  498.          break;
  499.  
  500.      default:
  501.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  502.          break;
  503.      }
  504.  
  505.      return (0L);
  506.  }
  507.  
  508.  
  509.  BOOL AppNewDocument(USHORT fsStyle, PSZ pszClassName)
  510.  {
  511.      register NPDOC npdocNew;
  512.      HWND hwndFrame, hwndClient;
  513.      HWND hwndHScroll, hwndVScroll;
  514.  
  515.      npdocNew = MDINewDocument(fsStyle, pszClassName);
  516.  
  517.      npdocNew->clrBackground = clrNext++;
  518.      if (clrNext > CLR_PALEGRAY)
  519.          clrNext = CLR_BACKGROUND;
  520.  
  521.      hwndFrame = npdocNew->hwndFrame;
  522.      hwndClient = WinWindowFromID(hwndFrame, FID_CLIENT);
  523.  
  524.      /*
  525.       * Setup the scrollbars.
  526.       */
  527.      hwndHScroll = WinWindowFromID(hwndFrame, FID_HORZSCROLL);
  528.      WinSendMsg(hwndHScroll, SBM_SETSCROLLBAR, MPFROMSHORT(0),
  529.              MPFROM2SHORT(0, 600));
  530.      hwndHScroll = WinWindowFromID(hwndFrame, ID_HORZSCROLL2);
  531.      WinSendMsg(hwndHScroll, SBM_SETSCROLLBAR, MPFROMSHORT(0),
  532.              MPFROM2SHORT(0, 600));
  533.  
  534.      hwndVScroll = WinWindowFromID(hwndFrame, FID_VERTSCROLL);
  535.      WinSendMsg(hwndVScroll, SBM_SETSCROLLBAR, MPFROMSHORT(0),
  536.              MPFROM2SHORT(0, 600));
  537.      hwndVScroll = WinWindowFromID(hwndFrame, ID_VERTSCROLL2);
  538.      WinSendMsg(hwndVScroll, SBM_SETSCROLLBAR, MPFROMSHORT(0),
  539.              MPFROM2SHORT(0, 600));
  540.  
  541.      /*
  542.       * Set the focus the client so the new window will be
  543.       * active when we show it.
  544.       */
  545.      WinSetFocus(HWND_DESKTOP, hwndClient);
  546.  
  547.      AddToWindowMenu(npdocNew);    /* Moved here from end of
  548.                                    MdiNewDocument routine so that the doc has
  549.                                    been activated, and therefore the main
  550.                                    window has a menu before attempting to add
  551.                                    the doc to the main window's menu */
  552.  
  553.  
  554.      /*
  555.       * Set the initial position of the frame window and make it visible.
  556.       */
  557.      MDISetInitialDocPos(hwndFrame);
  558.  
  559.      return (TRUE);
  560.  }
  561.  
  562.  MRESULT EXPENTRY AboutDlgProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  563.  /*
  564.      About... dialog procedure
  565.  */
  566.  {
  567.      switch(msg) {
  568.          case WM_COMMAND:
  569.              switch(COMMANDMSG(&msg)->cmd) {
  570.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  571.                  default: break;
  572.              }
  573.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  574.      }
  575.      return FALSE;
  576.  }
  577.  
  578.  
  579.  APPDATA.C
  580.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\MDI\APPDATA.C
  581.  
  582.  
  583.  #define INCL_WINSYS
  584.  #define INCL_WINCOMMON
  585.  #define INCL_WINMESSAGEMGR
  586.  #define INCL_WINACCELERATORS
  587.  #define INCL_WINMENUS
  588.  #define INCL_WINHEAP
  589.  #define INCL_WINPOINTERS
  590.  
  591.  #include <os2.h>
  592.  #include "app.h"
  593.  #include "mdi.h"
  594.  
  595.  char szMDIClass[] = "PM MDI Sample App";
  596.  char szDocClass[] = "PM MDI Document";
  597.  USHORT cxBorder, cyBorder, cyHScroll, cxVScroll, cyVScrollArrow;
  598.  USHORT cxScreen, cyScreen, cyIcon, cxByteAlign, cyByteAlign;
  599.  USHORT cxSizeBorder, cySizeBorder;
  600.  ULONG clrNext = CLR_BACKGROUND;
  601.  LONG rglDevCaps[(CAPS_VERTICAL_FONT_RES - CAPS_FAMILY)];
  602.  
  603.  /* Main globals */
  604.  HAB  hab;
  605.  HHEAP hHeap;
  606.  HMQ  hmqMDI;
  607.  HWND hwndMDI, hwndMDIFrame;
  608.  HWND hwndActiveDoc;
  609.  FONTMETRICS fmSystemFont;
  610.  NPDOC npdocFirst = NULL;
  611.  
  612.  /* Menu globals */
  613.  
  614.  
  615.  HWND hwndSysMenu;
  616.  
  617.  
  618.  APPDOC.C
  619.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\MDI\APPDOC.C
  620.  
  621.  /*
  622.      appdoc.c - MDI application
  623.      Created by Microsoft Corporation, 1989
  624.  */
  625.  #define INCL_WINSYS
  626.  #define INCL_WINCOMMON
  627.  #define INCL_WINMESSAGEMGR
  628.  #define INCL_WINFRAMEMGR
  629.  #define INCL_WINPOINTERS
  630.  #define INCL_WINMENUS
  631.  #define INCL_WINWINDOWMGR
  632.  #define INCL_WINACCELERATORS
  633.  #define INCL_WININPUT
  634.  #define INCL_WINHEAP
  635.  #define INCL_WINSCROLLBARS
  636.  #define INCL_WINRECTANGLES
  637.  #define INCL_WINCOUNTRY
  638.  #define INCL_GPIPRIMITIVES
  639.  #define INCL_GPILOGCOLORTABLE
  640.  
  641.  #include <os2.h>
  642.  #include <string.h>
  643.  #include <stdlib.h>
  644.  #include <stdio.h>
  645.  #include "app.h"
  646.  #include "appdata.h"
  647.  #include "mdi.h"
  648.  #include "mdidata.h"
  649.  
  650.  /* Function prototypes */
  651.  VOID AppHScroll(HWND hwnd, MPARAM mp1, MPARAM mp2);
  652.  VOID AppVScroll(HWND hwnd, MPARAM mp1, MPARAM mp2);
  653.  VOID AppEraseBackground(HWND hwnd, HPS hps);
  654.  VOID AppPaint(HWND hwnd);
  655.  VOID MDIClose(HWND hwndClient);
  656.  BOOL MDICreate(HWND);
  657.  BOOL MDIDestroy(HWND);
  658.  BOOL MDIActivate(HWND, BOOL);
  659.  
  660.  /*
  661.   * The array of RGB values for the rounded
  662.   * rectangles.
  663.   */
  664.  LONG aclrRGB[16] = {
  665.      RGB_RED, RGB_WHITE, RGB_GREEN, RGB_BLACK,
  666.      RGB_BLUE, RGB_WHITE, RGB_YELLOW, RGB_BLACK,
  667.      RGB_CYAN, RGB_BLACK, RGB_PINK, RGB_BLACK,
  668.      RGB_WHITE, RGB_PINK, RGB_BLACK, RGB_RED
  669.  };
  670.  
  671.  
  672.  
  673.  MRESULT EXPENTRY DocWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  674.  {
  675.  
  676.      switch (msg) {
  677.  
  678.      case WM_COMMAND:
  679.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  680.          break;
  681.  
  682.      case WM_CREATE:
  683.          if (MDICreate(hwnd) == FALSE)
  684.              return ( (MRESULT) TRUE);
  685.          break;
  686.  
  687.      case WM_DESTROY:
  688.          MDIDestroy(hwnd);
  689.          break;
  690.  
  691.      case WM_CLOSE:
  692.          MDIClose(hwnd);
  693.          break;
  694.  
  695.      case WM_HSCROLL:
  696.          AppHScroll(hwnd, mp1, mp2);
  697.          break;
  698.  
  699.      case WM_VSCROLL:
  700.          AppVScroll(hwnd, mp1, mp2);
  701.          break;
  702.  
  703.      case WM_ERASEBACKGROUND:
  704.          AppEraseBackground(hwnd, (HPS)mp1);
  705.          break;
  706.  
  707.      case WM_PAINT:
  708.          AppPaint(hwnd);
  709.          break;
  710.  
  711.      case WM_ACTIVATE:
  712.          MDIActivate(hwnd, (BOOL)SHORT1FROMMP(mp1));
  713.          break;
  714.  
  715.      default:
  716.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  717.          break;
  718.      }
  719.  
  720.      return (0L);
  721.  }
  722.  
  723.  
  724.  VOID AppEraseBackground(HWND hwnd, HPS hps)
  725.  {
  726.      RECTL rclPaint;
  727.      HWND hwndFrame, hwndClient;
  728.      register NPDOC npdoc;
  729.  
  730.      npdoc = NPDOCFROMCLIENT(hwnd);
  731.      hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  732.  
  733.      /*
  734.       * We know the main client is around so
  735.       * go ahead and erase it.
  736.       */
  737.      WinQueryWindowRect(hwnd, &rclPaint);
  738.      WinMapWindowPoints(hwnd, hwndFrame, (PPOINTL)&rclPaint, 2);
  739.      WinFillRect(hps, &rclPaint, npdoc->clrBackground);
  740.  
  741.      /*
  742.       * Now check to see which of the other client windows
  743.       * are around and erase them.
  744.       *
  745.       * We do all this to avoid erasing the splitbars.
  746.       */
  747.      if (npdoc->fs & DF_SPLITVERT) {
  748.  
  749.          hwndClient = WinWindowFromID(hwndFrame, ID_CLIENT2);
  750.          /*
  751.           * If it became invisible due to the frame
  752.           * window getting too small, then don't
  753.           * bother drawing.
  754.           */
  755.          if (WinIsWindowVisible(hwndClient) != FALSE) {
  756.              WinQueryWindowRect(hwndClient, &rclPaint);
  757.              WinMapWindowPoints(hwndClient, hwndFrame,
  758.                      (PPOINTL)&rclPaint, 2);
  759.              WinFillRect(hps, &rclPaint, npdoc->clrBackground);
  760.          }
  761.      }
  762.  
  763.      if (npdoc->fs & DF_SPLITHORZ) {
  764.  
  765.          hwndClient = WinWindowFromID(hwndFrame, ID_CLIENT3);
  766.          if (WinIsWindowVisible(hwndClient) != FALSE) {
  767.              WinQueryWindowRect(hwndClient, &rclPaint);
  768.              WinMapWindowPoints(hwndClient, hwndFrame,
  769.                      (PPOINTL)&rclPaint, 2);
  770.              WinFillRect(hps, &rclPaint, npdoc->clrBackground);
  771.          }
  772.      }
  773.  
  774.      /*
  775.       * If we're split in both directions, then there's
  776.       * a ID_CLIENT4 window.
  777.       */
  778.      if ((npdoc->fs & (DF_SPLITHORZ | DF_SPLITVERT)) ==
  779.              (DF_SPLITHORZ | DF_SPLITVERT)) {
  780.  
  781.          hwndClient = WinWindowFromID(hwndFrame, ID_CLIENT4);
  782.          if (WinIsWindowVisible(hwndClient) != FALSE) {
  783.              WinQueryWindowRect(hwndClient, &rclPaint);
  784.              WinMapWindowPoints(hwndClient, hwndFrame,
  785.                      (PPOINTL)&rclPaint, 2);
  786.              WinFillRect(hps, &rclPaint, npdoc->clrBackground);
  787.          }
  788.      }
  789.  }
  790.  
  791.  
  792.  VOID AppHScroll(HWND hwnd, MPARAM mp1, MPARAM mp2)
  793.  {
  794.      HWND hwndFrame;
  795.      NPDOC npdoc;
  796.      RECTL rclPaintBottom, rclPaintTop;
  797.      RECTL rclWindowBottom, rclWindowTop;
  798.      HWND hwndClientBottom, hwndClientTop;
  799.      HWND hwndScrollbar;
  800.      register NPVIEW npviewBottom, npviewTop;
  801.      SHORT posSlider, xOriginOld;
  802.      USHORT cmd, idScrollbar;
  803.  
  804.      hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  805.      npdoc = NPDOCFROMCLIENT(hwnd);
  806.  
  807.      idScrollbar = SHORT1FROMMP(mp1);
  808.  
  809.      switch (idScrollbar) {
  810.  
  811.      case FID_HORZSCROLL:
  812.          hwndClientTop = hwnd;
  813.          if (npdoc->fs & DF_SPLITHORZ) {
  814.              hwndClientBottom = WinWindowFromID(hwndFrame, ID_CLIENT3);
  815.          } else {
  816.              hwndClientBottom = NULL;
  817.          }
  818.          break;
  819.  
  820.      case ID_HORZSCROLL2:
  821.          hwndClientTop = WinWindowFromID(hwndFrame, ID_CLIENT2);
  822.          if (npdoc->fs & DF_SPLITHORZ) {
  823.              hwndClientBottom = WinWindowFromID(hwndFrame, ID_CLIENT4);
  824.          } else {
  825.              hwndClientBottom = NULL;
  826.          }
  827.          break;
  828.      }
  829.  
  830.      hwndScrollbar = WinWindowFromID(hwndFrame, idScrollbar);
  831.  
  832.      npviewTop = NPVIEWFROMCLIENT(hwndClientTop);
  833.      WinQueryWindowRect(hwndClientTop, &rclWindowTop);
  834.  
  835.      if (hwndClientBottom != NULL) {
  836.          npviewBottom = NPVIEWFROMCLIENT(hwndClientBottom);
  837.          WinQueryWindowRect(hwndClientBottom, &rclWindowBottom);
  838.      }
  839.  
  840.      posSlider = (SHORT) (ULONG) WinSendMsg(hwndScrollbar, SBM_QUERYPOS, NULL,
  841.  
  842.      cmd = SHORT2FROMMP(mp2);
  843.      switch (cmd) {
  844.  
  845.      case SB_LINELEFT:
  846.          posSlider -= 16;
  847.          break;
  848.  
  849.      case SB_LINERIGHT:
  850.          posSlider += 16;
  851.          break;
  852.  
  853.      case SB_PAGELEFT:
  854.          posSlider -= ((SHORT)rclWindowTop.xRight - 16);
  855.          break;
  856.  
  857.      case SB_PAGERIGHT:
  858.          posSlider += ((SHORT)rclWindowTop.xRight - 16);
  859.          break;
  860.  
  861.      case SB_SLIDERPOSITION:
  862.          posSlider = SHORT1FROMMP(mp2);
  863.          break;
  864.      }
  865.  
  866.      WinSendMsg(hwndScrollbar, SBM_SETPOS, MPFROMSHORT(posSlider), NULL);
  867.  
  868.      xOriginOld = npviewTop->xOrigin;
  869.      npviewTop->xOrigin = (SHORT) (ULONG) WinSendMsg(hwndScrollbar, SBM_QUERYP
  870.      WinScrollWindow(hwndClientTop, xOriginOld - npviewTop->xOrigin, 0,
  871.              NULL, NULL, NULL, &rclPaintTop, NULL);
  872.  
  873.      if (hwndClientBottom != NULL) {
  874.          xOriginOld = npviewBottom->xOrigin;
  875.          npviewBottom->xOrigin = npviewTop->xOrigin;
  876.          WinScrollWindow(hwndClientBottom, xOriginOld - npviewBottom->xOrigin,
  877.                  0, NULL, NULL, NULL, &rclPaintBottom, NULL);
  878.      }
  879.  
  880.      WinMapWindowPoints(hwndClientTop, hwndFrame, (PPOINTL)&rclPaintTop, 2);
  881.      WinInvalidateRect(hwndFrame, &rclPaintTop, TRUE);
  882.  
  883.      if (hwndClientBottom != NULL) {
  884.          WinMapWindowPoints(hwndClientBottom, hwndFrame, (PPOINTL)&rclPaintBot
  885.          WinInvalidateRect(hwndFrame, &rclPaintBottom, TRUE);
  886.      }
  887.  }
  888.  
  889.  
  890.  VOID AppVScroll(HWND hwnd, MPARAM mp1, MPARAM mp2)
  891.  {
  892.      HWND hwndFrame;
  893.      NPDOC npdoc;
  894.      RECTL rclPaintRight, rclPaintLeft;
  895.      RECTL rclWindowRight, rclWindowLeft;
  896.      HWND hwndClientRight, hwndClientLeft;
  897.      HWND hwndScrollbar;
  898.      register NPVIEW npviewRight, npviewLeft;
  899.      SHORT posSlider, yOriginOld;
  900.      USHORT cmd, idScrollbar;
  901.  
  902.      hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  903.      npdoc = NPDOCFROMCLIENT(hwnd);
  904.  
  905.      idScrollbar = SHORT1FROMMP(mp1);
  906.  
  907.      switch (idScrollbar) {
  908.  
  909.      case FID_VERTSCROLL:
  910.          hwndClientLeft = hwnd;
  911.          if (npdoc->fs & DF_SPLITVERT) {
  912.              hwndClientRight = WinWindowFromID(hwndFrame, ID_CLIENT2);
  913.          } else {
  914.              hwndClientRight = NULL;
  915.          }
  916.          break;
  917.  
  918.      case ID_VERTSCROLL2:
  919.          hwndClientLeft = WinWindowFromID(hwndFrame, ID_CLIENT3);
  920.          if (npdoc->fs & DF_SPLITVERT) {
  921.              hwndClientRight = WinWindowFromID(hwndFrame, ID_CLIENT4);
  922.          } else {
  923.              hwndClientRight = NULL;
  924.          }
  925.          break;
  926.      }
  927.  
  928.      hwndScrollbar = WinWindowFromID(hwndFrame, idScrollbar);
  929.  
  930.      npviewLeft = NPVIEWFROMCLIENT(hwndClientLeft);
  931.      WinQueryWindowRect(hwndClientLeft, &rclWindowLeft);
  932.  
  933.      if (hwndClientRight != NULL) {
  934.          npviewRight = NPVIEWFROMCLIENT(hwndClientRight);
  935.          WinQueryWindowRect(hwndClientRight, &rclWindowRight);
  936.      }
  937.  
  938.      posSlider = (SHORT) (ULONG) WinSendMsg(hwndScrollbar, SBM_QUERYPOS, NULL,
  939.  
  940.      cmd = SHORT2FROMMP(mp2);
  941.      switch (cmd) {
  942.  
  943.      case SB_LINEUP:
  944.          posSlider -= 16;
  945.          break;
  946.  
  947.      case SB_LINEDOWN:
  948.          posSlider += 16;
  949.          break;
  950.  
  951.      case SB_PAGEUP:
  952.          posSlider -= ((SHORT)rclWindowLeft.yTop - 16);
  953.          break;
  954.  
  955.      case SB_PAGEDOWN:
  956.          posSlider += ((SHORT)rclWindowLeft.yTop - 16);
  957.          break;
  958.  
  959.      case SB_SLIDERPOSITION:
  960.          posSlider = SHORT1FROMMP(mp2);
  961.          break;
  962.      }
  963.  
  964.      WinSendMsg(hwndScrollbar, SBM_SETPOS, MPFROMSHORT(posSlider), NULL);
  965.  
  966.      yOriginOld = npviewLeft->yOrigin;
  967.      npviewLeft->yOrigin = (SHORT) (ULONG) WinSendMsg(hwndScrollbar, SBM_QUERY
  968.      WinScrollWindow(hwndClientLeft, 0,  npviewLeft->yOrigin - yOriginOld,
  969.              NULL, NULL, NULL, &rclPaintLeft, NULL);
  970.  
  971.      if (hwndClientRight != NULL) {
  972.          yOriginOld = npviewRight->yOrigin;
  973.          npviewRight->yOrigin = npviewLeft->yOrigin;
  974.          WinScrollWindow(hwndClientRight, 0, npviewRight->yOrigin - yOriginOld
  975.                  NULL, NULL, NULL, &rclPaintRight, NULL);
  976.      }
  977.  
  978.      WinMapWindowPoints(hwndClientLeft, hwndFrame, (PPOINTL)&rclPaintLeft, 2);
  979.      WinInvalidateRect(hwndFrame, &rclPaintLeft, TRUE);
  980.  
  981.      if (hwndClientRight != NULL) {
  982.          WinMapWindowPoints(hwndClientRight, hwndFrame, (PPOINTL)&rclPaintRigh
  983.          WinInvalidateRect(hwndFrame, &rclPaintRight, TRUE);
  984.      }
  985.  }
  986.  
  987.  
  988.  VOID AppPaint(HWND hwnd)
  989.  {
  990.      HPS hps;
  991.      RECTL rclPaint, rclWindow, rclTest, rclDst;
  992.      POINTL ptl, ptlPatternRef;
  993.      register NPVIEW npview;
  994.      AREABUNDLE abnd;
  995.      LONG clrStart, clrEnd, clrInc, clr;
  996.      SHORT i, j;
  997.  
  998.      hps = WinBeginPaint(hwnd, (HPS)NULL, &rclPaint);
  999.  
  1000.      /*
  1001.       * Go into RGB mode.
  1002.       */
  1003.      GpiCreateLogColorTable(hps, 0L, LCOLF_RGB, 0L, 0L, NULL);
  1004.  
  1005.      /*
  1006.       * Make rclPaint an inclusive-inclusive rectangle
  1007.       * since that's how GpiBox() will be output.
  1008.       */
  1009.      rclPaint.xLeft--;
  1010.      rclPaint.yBottom--;
  1011.  
  1012.      npview = NPVIEWFROMCLIENT(hwnd);
  1013.  
  1014.      /*
  1015.       * Set the pattern to be at the top-left
  1016.       * since we're top-left aligning the bits.
  1017.       */
  1018.      WinQueryWindowRect(hwnd, (PRECTL)&rclWindow);
  1019.      ptlPatternRef.x = rclWindow.xLeft - npview->xOrigin;
  1020.      ptlPatternRef.y = rclWindow.yTop + npview->yOrigin;
  1021.      GpiSetPatternRefPoint(hps, &ptlPatternRef);
  1022.  
  1023.      for (i = 0; i < 8; i++) {
  1024.  
  1025.          clr = clrStart = aclrRGB[i * 2];
  1026.          clrEnd = aclrRGB[(i * 2) + 1];
  1027.          clrInc = (clrEnd - clrStart) / 8;
  1028.  
  1029.          for (j = 0; j < 8; j++) {
  1030.              abnd.lColor = clr + (j * clrInc);
  1031.              GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, (PBUNDLE)&abnd);
  1032.  
  1033.              /*
  1034.               * Only draw the box if it's going to
  1035.               * be visible in the update region.
  1036.               */
  1037.              WinSetRect(NULL, &rclTest, 10 + (i * 75),
  1038.                      (SHORT)rclWindow.yTop - 75 - (j * 75), 75 + (i * 75),
  1039.                      (SHORT)rclWindow.yTop - 10 - (j * 75));
  1040.  
  1041.              WinOffsetRect(NULL, &rclTest, -npview->xOrigin, npview->yOrigin);
  1042.  
  1043.              if (WinIntersectRect(NULL, &rclDst, &rclTest, &rclPaint)) {
  1044.  
  1045.                  ptl.x = rclTest.xLeft;
  1046.                  ptl.y = rclTest.yTop;
  1047.                  GpiSetCurrentPosition(hps, (PPOINTL)&ptl);
  1048.  
  1049.                  ptl.x = rclTest.xRight;
  1050.                  ptl.y = rclTest.yBottom;
  1051.                  GpiBox(hps, DRO_OUTLINEFILL, (PPOINTL)&ptl, 40L, 40L);
  1052.              }
  1053.          }
  1054.      }
  1055.  
  1056.      WinEndPaint(hps);
  1057.  }
  1058.  
  1059.  
  1060.  APPINIT.C
  1061.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\MDI\APPINIT.C
  1062.  
  1063.  /*
  1064.      mdiinit.c - MDI initialization funtions.
  1065.      Created by Microsoft Corporation, 1989
  1066.  */
  1067.  #define INCL_WINSYS
  1068.  #define INCL_WINCOMMON
  1069.  #define INCL_WINMESSAGEMGR
  1070.  #define INCL_WINPOINTERS
  1071.  #define INCL_WININPUT
  1072.  #define INCL_WINMENUS
  1073.  #define INCL_WINFRAMEMGR
  1074.  #define INCL_WINWINDOWMGR
  1075.  #define INCL_WINRECTANGLES
  1076.  #define INCL_WINHEAP
  1077.  #define INCL_GPIBITMAPS
  1078.  #define INCL_GPILCIDS
  1079.  #define INCL_DEV
  1080.  
  1081.  #include <os2.h>
  1082.  #include "app.h"
  1083.  #include "appdata.h"
  1084.  #include "mdi.h"
  1085.  #include "mdidata.h"
  1086.  
  1087.  
  1088.  /* Function prototypes */
  1089.  BOOL RegisterWindowClasses(VOID);
  1090.  VOID InitSysValues(VOID);
  1091.  
  1092.  
  1093.  BOOL AppInit(VOID)
  1094.  {
  1095.      ULONG ctlData;
  1096.      HPS hps;
  1097.      HDC hdc;
  1098.  
  1099.      hab = WinInitialize(0);
  1100.  
  1101.      hmqMDI = WinCreateMsgQueue(hab, 0);
  1102.  
  1103.      if (!RegisterWindowClasses())
  1104.          return(FALSE);
  1105.  
  1106.      ctlData = FCF_TITLEBAR | FCF_MINMAX | FCF_SIZEBORDER | FCF_SYSMENU |
  1107.                FCF_MENU | FCF_TASKLIST | FCF_SHELLPOSITION | FCF_ICON;
  1108.  
  1109.      hwndMDIFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
  1110.              (VOID FAR *)&ctlData, szMDIClass, (PSZ)NULL,
  1111.              WS_VISIBLE | WS_CLIPCHILDREN, NULL, IDR_MDI,
  1112.              (HWND FAR *)&hwndMDI);
  1113.  
  1114.  
  1115.      if (hwndMDIFrame == NULL)
  1116.          return(FALSE);
  1117.  
  1118.  /* MULTIPLEMENU */
  1119.  
  1120.      /* Remember the first menu so we can put it back when all the documents a
  1121.         closed */
  1122.      hwndFirstMenu=WinWindowFromID(hwndMDIFrame, FID_MENU);
  1123.  
  1124.      hHeap = WinCreateHeap(0, 0, 0, 0, 0, 0);
  1125.  
  1126.      if (hHeap == NULL)
  1127.          return(FALSE);
  1128.  
  1129.      hps = WinGetPS(hwndMDI);
  1130.  
  1131.      hdc = GpiQueryDevice(hps);
  1132.      DevQueryCaps(hdc, CAPS_FAMILY, CAPS_VERTICAL_FONT_RES, (PLONG)rglDevCaps)
  1133.  
  1134.      WinReleasePS(hps);
  1135.  
  1136.      InitSysValues();
  1137.  
  1138.      return(TRUE);
  1139.  }
  1140.  
  1141.  
  1142.  VOID InitSysValues(VOID)
  1143.  {
  1144.      cyTitlebar = (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
  1145.      cyIcon = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
  1146.  
  1147.      cxBorder = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  1148.      cyBorder = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
  1149.  
  1150.      cxSizeBorder = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);
  1151.      cySizeBorder = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
  1152.  
  1153.      cxByteAlign = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXBYTEALIGN);
  1154.      cyByteAlign = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYBYTEALIGN);
  1155.  
  1156.      cxVScroll = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
  1157.      cyVScrollArrow = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYVSCROLLARROW
  1158.      cyHScroll = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  1159.  
  1160.      cxScreen = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  1161.      cyScreen = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  1162.  
  1163.      cxMinmaxButton = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXMINMAXBUTTON
  1164.  }
  1165.  
  1166.  
  1167.  BOOL RegisterWindowClasses(VOID)
  1168.  {
  1169.      if (!WinRegisterClass(NULL, szMDIClass, (PFNWP)MDIWndProc,
  1170.              CS_SYNCPAINT, 0))
  1171.          return(FALSE);
  1172.  
  1173.      if (!WinRegisterClass(NULL, szDocClass, (PFNWP)DocWndProc,
  1174.              0L, sizeof(NPVIEW)))
  1175.          return(FALSE);
  1176.  
  1177.      return(TRUE);
  1178.  }
  1179.  
  1180.  
  1181.  VOID AppTerminate(VOID)
  1182.  {
  1183.      WinDestroyWindow(hwndMDIFrame);
  1184.  
  1185.      WinDestroyHeap(hHeap);
  1186.  
  1187.      WinDestroyMsgQueue(hmqMDI);
  1188.  
  1189.      WinTerminate(hab);
  1190.  }
  1191.  
  1192.  
  1193.  ARRANGE.C
  1194.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\MDI\ARRANGE.C
  1195.  
  1196.  /***************************************************************************\
  1197.  * ARRANGE.c - This file contains code to do window arrangment.
  1198.  *
  1199.  * Created by Microsoft Corporation, 1989
  1200.  \***************************************************************************/
  1201.  
  1202.  #define INCL_WINSYS
  1203.  #define INCL_WINCOMMON
  1204.  #define INCL_WINMESSAGEMGR
  1205.  #define INCL_WINPOINTERS
  1206.  #define INCL_WININPUT
  1207.  #define INCL_WINMENUS
  1208.  #define INCL_WINFRAMEMGR
  1209.  #define INCL_WINWINDOWMGR
  1210.  #define INCL_WINRECTANGLES
  1211.  #define INCL_WINHEAP
  1212.  #include <os2.h>
  1213.  #include "app.h"
  1214.  #include "appdata.h"
  1215.  #include "mdi.h"
  1216.  #include "mdidata.h"
  1217.  
  1218.  
  1219.  MINMAXFIX  /* add hack to keep the min/max icons in sync with reality */
  1220.  
  1221.  /* internal function prototypes */
  1222.  BOOL SetTilePositions(PRECTL prc, SHORT cWnd, PSWP aswp);
  1223.  SHORT CeilSquareRoot(USHORT us);
  1224.  BOOL SetCascadePositions(PRECTL prc, SHORT cWnd, PSWP aswp);
  1225.  BOOL SetCascadeParams(PRECTL prc, SHORT *pxEdge, SHORT *pyEdge,
  1226.                        SHORT *pxDelta, SHORT *pyDelta, SHORT *cMaxWnd);
  1227.  BOOL GetArrangeSwp(USHORT *, SWP *, USHORT *, SWP *);
  1228.  BOOL GetArrangeRectangle(PRECTL, BOOL);
  1229.  BOOL ArrangeIconPositions(USHORT, PSWP);
  1230.  
  1231.  /* internal constants */
  1232.  #define CASC_EDGE_NUM       2
  1233.  #define CASC_EDGE_DENOM     3
  1234.  
  1235.  /* local constants */
  1236.  #define ICON_PARK_NUM       5
  1237.  #define ICON_PARK_DENOM     3
  1238.  #define CLASS_NAME_LENGTH   8
  1239.  
  1240.  /***************************************************************************\
  1241.  * ArrangeWindowPositions
  1242.  *
  1243.  * This function sets positions for arranging windows nicely in a rectangle.
  1244.  * The hwnd field of each SWP structure should be set by the user, either
  1245.  * before or after calling this function.  The function sets all other
  1246.  * fields.  The SWP array can then be passed to WinSetMultWindowPos() to do
  1247.  * the physical arrangement.  There are two arrangement styles available,
  1248.  * AWP_TILED and AWP_CASCADED.
  1249.  *
  1250.  * AWP_TILED:
  1251.  *
  1252.  * The tiles are generated by rows, top left (first) to bottom right (last).
  1253.  * Each row has the same number of tiles.  The number of tiles in each
  1254.  * column will differ by at most one, with each column containing one fewer
  1255.  * tile to the left of the other columns.
  1256.  *
  1257.  * AWP_CASCADED:
  1258.  *
  1259.  * The windows are generated bottom right (first) to top left (last).
  1260.  *
  1261.  * Parameters:
  1262.  *   prc:    rectangle to contain the tiled windows
  1263.  *   cWnd:   number of windows to tile
  1264.  *   aswp:   array of SWP structures, one for each tile window
  1265.  *   fStyle: the style to arrange the windows
  1266.  \***************************************************************************/
  1267.  
  1268.  BOOL ArrangeWindowPositions(PRECTL prc, SHORT cWnd, PSWP aswp, USHORT fStyle)
  1269.  {
  1270.      /* check validity of input rectangle */
  1271.      if ((prc->xRight - prc->xLeft < 1) || (prc->yTop - prc->yBottom < 1)) {
  1272.          return FALSE;
  1273.      }
  1274.  
  1275.      /* set window positions */
  1276.      switch (fStyle) {
  1277.      case AWP_TILED:
  1278.          return SetTilePositions(prc, cWnd, aswp);
  1279.      case AWP_CASCADED:
  1280.          return SetCascadePositions(prc, cWnd, aswp);
  1281.      default:
  1282.          return FALSE;
  1283.      }
  1284.  }
  1285.  
  1286.  
  1287.  /***************************************************************************\
  1288.  * SetTilePositions
  1289.  *
  1290.  * This function sets positions for tiling windows in a rectangle.
  1291.  *
  1292.  * NOTE:
  1293.  *   There are a few subtleties to this code:
  1294.  *
  1295.  *   The algorithm lays tiles in a modified NxN grid.  It can be shown
  1296.  *   that any positive number of tiles can be laid out in such a grid of
  1297.  *   N columns so that each column has at least N-2 tiles and no column
  1298.  *   has more than one tile more than any other.  Proof left to the
  1299.  *   interested reader.
  1300.  *
  1301.  *   The tiles coordinates are not generated by stepping over a fixed
  1302.  *   interval since this will not usually fill the rectangle completely.
  1303.  *   Thus the offset at each step is calculated from the previous tile
  1304.  *   to the correct fractional position within the whole rectangle.
  1305.  *
  1306.  *   Since the last "row" of tiles may not have any members in the beginning
  1307.  *   columns, these tiles are addressed differently in the SWP array to
  1308.  *   account for the "missing" tiles.
  1309.  *
  1310.  * Parameters:
  1311.  *   prc:        rectangle to contain the tiled windows
  1312.  *   cWnd:        number of windows to tile the rectangle with
  1313.  *   aswp:        array of SWP structures, one for each tile window
  1314.  \***************************************************************************/
  1315.  
  1316.  BOOL SetTilePositions(PRECTL prc, SHORT cWnd, PSWP aswp)
  1317.  {
  1318.      register SHORT usRoot;
  1319.      register SHORT cExtras;
  1320.      SHORT iChange;
  1321.      SHORT cDiff;
  1322.      SHORT x, y, cx, cy;
  1323.      SHORT iRow, iCol;
  1324.  
  1325.      /* get grid dimensions */
  1326.      usRoot = CeilSquareRoot(cWnd);
  1327.      cExtras = usRoot * usRoot - cWnd;
  1328.  
  1329.      /* find column where number of rows increases and find initial
  1330.         difference of rows versus columns */
  1331.      if (cExtras >= usRoot) {
  1332.          iChange = cExtras - usRoot;
  1333.          cDiff = 2;
  1334.      } else {
  1335.          iChange = cExtras;
  1336.          cDiff = 1;
  1337.      }
  1338.  
  1339.      /* assign x coordinates */
  1340.      x = (SHORT)prc->xLeft;
  1341.      cx = 0;
  1342.      for (iCol = 0; iCol < usRoot; iCol++) {
  1343.          x += cx - cxBorder;
  1344.          cx = ((SHORT)prc->xLeft) +
  1345.               (((SHORT)(prc->xRight - prc->xLeft)) * (iCol + 1)) / usRoot -
  1346.               x + cxBorder;
  1347.          for (iRow = 0; iRow < usRoot - cDiff; iRow++) {
  1348.              aswp[iRow * usRoot + iCol].x = x;
  1349.              aswp[iRow * usRoot + iCol].cx = cx;
  1350.              aswp[iRow * usRoot + iCol].fs = SWP_SIZE | SWP_MOVE;
  1351.          }
  1352.          /* assign "extra" row */
  1353.          if (iCol >= iChange) {
  1354.              aswp[iRow * usRoot + iCol - iChange].x = x;
  1355.              aswp[iRow * usRoot + iCol - iChange].cx = cx;
  1356.              aswp[iRow * usRoot + iCol - iChange].fs = SWP_SIZE | SWP_MOVE;
  1357.          }
  1358.      }
  1359.  
  1360.      /* assign y coordinates, columns without extra row */
  1361.      y = (SHORT)prc->yBottom;
  1362.      cy = 0;
  1363.      for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--) {
  1364.          y += cy - cyBorder;
  1365.          cy = ((SHORT)prc->yBottom) +
  1366.               (((SHORT)(prc->yTop - prc->yBottom)) * (usRoot - cDiff - iRow))
  1367.                  (usRoot - cDiff) - y + cyBorder;
  1368.          for (iCol = 0; iCol < iChange; iCol++) {
  1369.              aswp[iRow * usRoot + iCol].y = y;
  1370.              aswp[iRow * usRoot + iCol].cy = cy;
  1371.          }
  1372.      }
  1373.  
  1374.      /* assign y coordinates, columns with extra row */
  1375.      /* do last row first (different offsets) */
  1376.      y = (SHORT)prc->yBottom - cyBorder;
  1377.      cy = ((SHORT)(prc->yTop - prc->yBottom)) / (usRoot - cDiff + 1) +
  1378.           2 * cyBorder;
  1379.      for (iCol = iChange; iCol < usRoot; iCol++) {
  1380.          aswp[usRoot * (usRoot - cDiff) + iCol - iChange].y = y;
  1381.          aswp[usRoot * (usRoot - cDiff) + iCol - iChange].cy = cy;
  1382.      }
  1383.      for (iRow = usRoot - cDiff - 1; iRow >= 0; iRow--) {
  1384.          y += cy - cyBorder;
  1385.          cy = ((SHORT)(prc->yBottom)) +
  1386.                  (((SHORT)(prc->yTop - prc->yBottom)) * (usRoot - cDiff - iRow
  1387.                  / (usRoot - cDiff + 1) - y + cyBorder;
  1388.          for (iCol = iChange; iCol < usRoot; iCol++) {
  1389.              aswp[iRow * usRoot + iCol].y = y;
  1390.              aswp[iRow * usRoot + iCol].cy = cy;
  1391.          }
  1392.      }
  1393.  
  1394.      return TRUE;
  1395.  }
  1396.  
  1397.  
  1398.  /***************************************************************************\
  1399.  * CeilSquareRoot
  1400.  *
  1401.  * This function returns the smallest integer greater or equal to the square
  1402.  * root of an unsigned 16 bit integer.
  1403.  *
  1404.  * Parameter:
  1405.  *   us: value to take the root of
  1406.  \***************************************************************************/
  1407.  
  1408.  SHORT CeilSquareRoot(register USHORT us)
  1409.  {
  1410.      register SHORT i;
  1411.  
  1412.      /* prevent overflow of large numbers */
  1413.      if (us > 0xFE * 0xFE)
  1414.          return 0xFF;
  1415.  
  1416.      /* iterate up past root */
  1417.      for (i = 0; i*i < (SHORT) us; i++)
  1418.          ;
  1419.      return i;
  1420.  }
  1421.  
  1422.  
  1423.  /***************************************************************************\
  1424.  * SetCascadePositions
  1425.  *
  1426.  * This function sets positions for cascading windows in a rectangle.
  1427.  *
  1428.  * Parameters:
  1429.  *   prc:        rectangle to contain the cascaded windows
  1430.  *   cWnd:        number of windows to cascade
  1431.  *   aswp:        array of SWP structures, one for each cascaded window
  1432.  \***************************************************************************/
  1433.  
  1434.  BOOL SetCascadePositions(PRECTL prc, SHORT cWnd, PSWP aswp)
  1435.  {
  1436.      SHORT xEdge, yEdge;
  1437.      SHORT xDelta, yDelta;
  1438.      SHORT cMaxWnd;
  1439.      register SHORT x, y;
  1440.      SHORT i, j;
  1441.      RECTL rc;
  1442.  
  1443.      /* set cascade parameters */
  1444.      rc.xLeft = prc->xLeft - cxBorder;
  1445.      rc.xRight = prc->xRight + cyBorder;
  1446.      rc.yBottom = prc->yBottom - cyBorder;
  1447.      rc.yTop = prc->yTop + cyBorder;
  1448.      if (!SetCascadeParams((PRECTL)&rc, &xEdge, &yEdge, &xDelta, &yDelta,
  1449.                            &cMaxWnd)) {
  1450.          return FALSE;
  1451.      }
  1452.  
  1453.      if (cWnd <= cMaxWnd) {
  1454.          /* only one run needed; move to top left corner */
  1455.          x = (SHORT)rc. xLeft;
  1456.          y = (SHORT)rc. yTop - yEdge;
  1457.          for (i = cWnd - 1; i >= 0; i--) {
  1458.              aswp[i].x = x;
  1459.              aswp[i].y = y;
  1460.              aswp[i].cx = xEdge;
  1461.              aswp[i].cy = yEdge;
  1462.              aswp[i].fs = SWP_SIZE | SWP_MOVE;
  1463.              x += xDelta;
  1464.              y -= yDelta;
  1465.          }
  1466.  
  1467.      } else {
  1468.  
  1469.          /* multiple runs necessary; start at bottom right, iterate up to
  1470.             top left */
  1471.  
  1472.          i = 0;
  1473.  
  1474.          while (i < cWnd) {
  1475.  
  1476.              /* even run */
  1477.              x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta;
  1478.              y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta;
  1479.              for (j = 0; j < cMaxWnd; j++) {
  1480.                  aswp[i].x = x;
  1481.                  aswp[i].y = y;
  1482.                  aswp[i].cx = xEdge;
  1483.                  aswp[i].cy = yEdge;
  1484.                  aswp[i].fs = SWP_SIZE | SWP_MOVE;
  1485.                  x -= xDelta;
  1486.                  y += yDelta;
  1487.                  if (++i >= cWnd)
  1488.                      break;
  1489.              }
  1490.  
  1491.              if (i >= cWnd)
  1492.                  break;
  1493.  
  1494.              /* odd run, offset by half delta y, one and one half delta x */
  1495.              x = ((SHORT)rc. xLeft) + (cMaxWnd-1) * xDelta + xDelta/2;
  1496.              y = ((SHORT)rc. yTop) - yEdge - (cMaxWnd-1) * yDelta + yDelta/2;
  1497.              for (j = 0; j < cMaxWnd - 1; j++) {
  1498.                  aswp[i].x = x;
  1499.                  aswp[i].y = y;
  1500.                  aswp[i].cx = xEdge;
  1501.                  aswp[i].cy = yEdge;
  1502.                  aswp[i].fs = SWP_SIZE | SWP_MOVE;
  1503.                  x -= xDelta;
  1504.                  y += yDelta;
  1505.                  if (++i >= cWnd)
  1506.                      break;
  1507.              }
  1508.          }
  1509.      }
  1510.  
  1511.      return TRUE;
  1512.  }
  1513.  
  1514.  
  1515.  /***************************************************************************\
  1516.  * SetCascadeParams
  1517.  *
  1518.  * This function sets parameters for cascading windows.        The window edge
  1519.  * are based on a fraction CASC_EDGE_NUM/CASC_EDGE_DENOM of the rectangle.
  1520.  * The x delta is four system font characters across, the y delta is two
  1521.  * system lines high.
  1522.  *
  1523.  * Parameters:
  1524.  *   prc:        rectangle to contain the windows
  1525.  *   pxEdge:        width of the cascaded windows
  1526.  *   pyEdge:        height of the cascaded windows
  1527.  *   pxDelta:        x cascade offset
  1528.  *   pyDelta:        y cascade offset
  1529.  *   pcMaxWnd:        maximum number of windows in a cascade
  1530.  \***************************************************************************/
  1531.  
  1532.  BOOL SetCascadeParams(PRECTL prc, SHORT *pxEdge, SHORT *pyEdge, SHORT *pxDelt
  1533.          SHORT *pyDelta, SHORT *pcMaxWnd)
  1534.  {
  1535.      register SHORT xEdge, yEdge;
  1536.      SHORT xDelta, yDelta;
  1537.      SHORT cMaxWnd;
  1538.  
  1539.      /* get x and y deltas from system values */
  1540.      xDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER)) +
  1541.               LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CXMINMAXBUTTON)) / 2
  1542.      yDelta = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER)) +
  1543.               LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR))
  1544.               - cyBorder;
  1545.  
  1546.      /* get initial cut at yEdge using fraction */
  1547.      yEdge = (((SHORT)(prc->yTop - prc->yBottom)) * CASC_EDGE_NUM) /
  1548.              CASC_EDGE_DENOM;
  1549.  
  1550.      /* determine maximum number of deltas used per run */
  1551.      cMaxWnd = (((SHORT)(prc->yTop - prc->yBottom)) - yEdge) / yDelta;
  1552.  
  1553.      /* set x and y edges so full cascade will fill rectangle completely */
  1554.      xEdge = ((SHORT)(prc->xRight - prc->xLeft)) - xDelta/2 - cMaxWnd * xDelta
  1555.      yEdge = ((SHORT)(prc->yTop - prc->yBottom)) - cMaxWnd * yDelta;
  1556.  
  1557.      /* check that values are reasonable */
  1558.      if (cMaxWnd < 1 || xEdge < 1 || yEdge < 1) {
  1559.          return FALSE;
  1560.      }
  1561.  
  1562.      *pxEdge = xEdge;
  1563.      *pyEdge = yEdge;
  1564.      *pxDelta = xDelta;
  1565.      *pyDelta = yDelta;
  1566.      /* return cMaxWnd as the maximum number of windows in a cascade */
  1567.      *pcMaxWnd = cMaxWnd + 1;
  1568.  
  1569.      return TRUE;
  1570.  }
  1571.  
  1572.  
  1573.  /***************************************************************************\
  1574.  * ArrangeWindows
  1575.  *
  1576.  * This function arranges application document windows.
  1577.  *
  1578.  * Returns:
  1579.  *   TRUE if successful
  1580.  *   FALSE otherwise
  1581.  \***************************************************************************/
  1582.  
  1583.  BOOL ArrangeWindows(USHORT fStyle)
  1584.  {
  1585.      USHORT cswpWnd, cswpIcon;
  1586.      RECTL rcl;
  1587.      register BOOL fReturn = FALSE;
  1588.      SWP NEAR *npswpWnd;
  1589.      SWP NEAR *npswpIcon;
  1590.  
  1591.      npswpWnd = (SWP NEAR *) WinAllocMem(hHeap, sizeof(SWP) * cDocs);
  1592.      npswpIcon = (SWP NEAR *) WinAllocMem(hHeap, sizeof(SWP) * cDocs);
  1593.  
  1594.      GetArrangeSwp(&cswpWnd, npswpWnd, &cswpIcon, npswpIcon);
  1595.  
  1596.      GetArrangeRectangle((PRECTL)&rcl, (BOOL)cswpIcon);
  1597.  
  1598.      /* set window positions */
  1599.      if (!ArrangeWindowPositions((PRECTL)&rcl, cswpWnd, (PSWP)npswpWnd, fStyle
  1600.          !ArrangeIconPositions(cswpIcon, (PSWP)npswpIcon)) {
  1601.          goto ARRANGE_CLEANUP;
  1602.      }
  1603.  
  1604.  #if 1
  1605.      /* rearrange the windows */
  1606.      WinSetMultWindowPos(NULL, (PSWP)npswpWnd, cswpWnd);
  1607.      WinSetMultWindowPos(NULL, (PSWP)npswpIcon, cswpIcon);
  1608.  #endif
  1609.      fReturn = TRUE;
  1610.  
  1611.  ARRANGE_CLEANUP:
  1612.      WinFreeMem(hHeap, (NPBYTE)npswpWnd, sizeof(SWP) * cDocs);
  1613.      WinFreeMem(hHeap, (NPBYTE)npswpIcon, sizeof(SWP) * cDocs);
  1614.  
  1615.      return fReturn;
  1616.  }
  1617.  
  1618.  /***************************************************************************\
  1619.  * GetArrangeHandles
  1620.  *
  1621.  * This function generates the handles of all windows to be arranged and
  1622.  * creates an array of SWP structures containing those handles.  Minimized
  1623.  * and non-minimized windows are separated.  Non-frame, invisible and
  1624.  * non-sizeable windows are ignored.
  1625.  *
  1626.  * Parameter:
  1627.  *   npcswpWnd:        number of nonminimized windows found
  1628.  *   npswpWnd:         array of SWP structures for nonminimized windows
  1629.  *   npcswpIcon:       number of minimized windows found
  1630.  *   npswpIcon:        array of SWP structures for minimized windows
  1631.  *
  1632.  * Returns:
  1633.  *   TRUE if successful
  1634.  *   FALSE otherwise
  1635.  \***************************************************************************/
  1636.  
  1637.  BOOL GetArrangeSwp(USHORT *npcswpWnd, SWP *npswpWnd, USHORT *npcswpIcon,
  1638.          SWP *npswpIcon)
  1639.  {
  1640.      register USHORT cWnd, cIcon;
  1641.      ULONG ulStyle;
  1642.      HWND hwnd;
  1643.      register NPDOC npdoc;
  1644.  
  1645.      cWnd = 0;
  1646.      cIcon = 0;
  1647.  
  1648.      /* enumerate windows and selectively add them to the arrange lists */
  1649.      for (hwnd = WinQueryWindow(hwndMDI, QW_TOP, FALSE);
  1650.           hwnd;
  1651.           hwnd = WinQueryWindow(hwnd, QW_NEXT, FALSE)) {
  1652.  
  1653.          /* make sure the window is visible and owned by the app client window
  1654.          ulStyle = WinQueryWindowULong(hwnd, QWL_STYLE);
  1655.          if (WinQueryWindow(hwnd, QW_OWNER, FALSE) ||
  1656.              !(ulStyle & WS_VISIBLE)) {
  1657.              continue;
  1658.          }
  1659.  
  1660.          if (ulStyle & WS_MINIMIZED) {
  1661.              npswpIcon->hwnd = hwnd;
  1662.              npswpIcon++;
  1663.              cIcon++;
  1664.          } else {
  1665.              /* restore maximized windows */
  1666.              if (ulStyle & WS_MAXIMIZED) {
  1667.  
  1668.  #ifdef MINMAXFIX
  1669.                  /* Bring the min/max buttons back to life for a moment so
  1670.                     they stay in sync when the window is restored.  Then put
  1671.                     them back to the object window 07-Sep-1989 johnba
  1672.                  */
  1673.  
  1674.                  npdoc = NPDOCFROMCLIENT(WinWindowFromID(hwnd,FID_CLIENT));
  1675.                  WinSetParent(npdoc->hwndMinmax, hwnd, FALSE);
  1676.  #endif
  1677.                  WinSetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_RESTORE );
  1678.  #ifdef MINMAXFIX
  1679.  
  1680.  
  1681.                  if (hwndActiveDoc != hwnd) {
  1682.                      WinSetParent(npdoc->hwndMinmax, HWND_OBJECT, FALSE);
  1683.                      WinSendMsg(hwnd, WM_UPDATEFRAME, 0L, 0L);
  1684.                      }
  1685.  #endif
  1686.                  }
  1687.              npswpWnd->hwnd = hwnd;
  1688.              npswpWnd++;
  1689.              cWnd++;
  1690.          }
  1691.      }
  1692.  
  1693.      *npcswpWnd = cWnd;
  1694.      *npcswpIcon = cIcon;
  1695.      return TRUE;
  1696.  }
  1697.  
  1698.  
  1699.  /***************************************************************************\
  1700.  * GetArrangeRectangle
  1701.  *
  1702.  * This function determines the area in which task windows are arranged.
  1703.  *
  1704.  * Parameter:
  1705.  *   prc:        the generated area rectangle
  1706.  *   fIconPark:        specifies if room should be made for icon parking lot
  1707.  *
  1708.  * Returns:
  1709.  *   TRUE if successful
  1710.  *   FALSE otherwise
  1711.  \***************************************************************************/
  1712.  
  1713.  BOOL GetArrangeRectangle(PRECTL prc, BOOL fIconPark)
  1714.  {
  1715.      register USHORT yIcon;
  1716.      register SHORT cxBorderInset;
  1717.  
  1718.      /* get dimensions of desktop window */
  1719.      WinQueryWindowRect(hwndMDI, prc);
  1720.  
  1721.      cxBorderInset = (SHORT)(WinQuerySysValue(HWND_DESKTOP, SV_CXBYTEALIGN) -
  1722.                         WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER));
  1723.      WinInflateRect(NULL, prc, -cxBorderInset, -cxBorderInset *
  1724.              (cyBorder / cxBorder));
  1725.  
  1726.      if (fIconPark) {
  1727.          /* make room for single row of icon carpark */
  1728.          yIcon = LOUSHORT(WinQuerySysValue(HWND_DESKTOP, SV_CYICON));
  1729.          prc->yBottom += (yIcon * ICON_PARK_NUM) / ICON_PARK_DENOM;
  1730.      }
  1731.  
  1732.      return TRUE;
  1733.  }
  1734.  
  1735.  /***************************************************************************\
  1736.  * ArrangeIconPositions
  1737.  *
  1738.  * This function sets positions for minimized windows.
  1739.  *
  1740.  * Parameters:
  1741.  *   cIcon:        number of icons to position
  1742.  *   aswp:        array of SetWindowPos structures for those icons
  1743.  *
  1744.  * Returns:
  1745.  *   TRUE if successful
  1746.  *   FALSE otherwise
  1747.  \***************************************************************************/
  1748.  
  1749.  BOOL ArrangeIconPositions(USHORT cIcon, PSWP aswpIcon)
  1750.  {
  1751.      register USHORT i;
  1752.  
  1753.      for (i = 0; i < cIcon; i++) {
  1754.          aswpIcon[i].x = 0;
  1755.          aswpIcon[i].y = 0;
  1756.          aswpIcon[i].fs = SWP_MOVE;
  1757.      }
  1758.  
  1759.      return TRUE;
  1760.  }
  1761.  
  1762.  
  1763.  AVIO.C
  1764.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BROWSE\AVBROWSE\AVIO.C
  1765.  
  1766.  /*
  1767.      avio.c -- AVIO action routines
  1768.  
  1769.      Implements scrollbars, sets up an AVIO Presentation Space
  1770.  */
  1771.  #define  INCL_AVIO
  1772.  #define         INCL_DEV
  1773.  #define  INCL_VIO
  1774.  #define  INCL_WINWINDOWMGR
  1775.  #define  INCL_WINSYS
  1776.  #define  INCL_WINMESSAGEMGR
  1777.  #define  INCL_WINTRACKRECT
  1778.  #define  INCL_WINFRAMEMGR
  1779.  #define  INCL_WINSCROLLBARS
  1780.  #include <os2.h>
  1781.  <string.h>        /* One strlen() call in the Blast() macro */
  1782.  "avio.h"        /* Get Avio-prefixed routine prototypes   */
  1783.  /*
  1784.      Constants
  1785.  */
  1786.  char        Blank[2] = { 0x20, 0x07 };        /* <Space> + EGA white attribut
  1787.  /*
  1788.      Macros to make the code more readable
  1789.  */
  1790.  /* Upper and Lower Bound Calculations */
  1791.  #define        Abs(a)                (((a) > 0) ? (a) : (-(a)))
  1792.  #define        Min(a,b)        (((a) < (b)) ? (a) : (b))
  1793.  #define        Max(a,b)        (((a) > (b)) ? (a) : (b))
  1794.  #define LowerBound(pos, disp, lbound) Max(pos - disp, lbound)
  1795.  #define UpperBound(pos, disp, ubound) Min(pos + disp, ubound)
  1796.  
  1797.  /* Scroll Bar Abbreviations */
  1798.  #define DisableSB(hSB)        WinSetParent(hSB, HWND_OBJECT, TRUE)
  1799.  #define EnableSB(hSB)         WinSetParent(hSB, hWndFrame,   TRUE)
  1800.  #define SetScroll(h, pos, max) \
  1801.      WinSendMsg(h, SBM_SETSCROLLBAR, MPFROM2SHORT(pos, 0), MPFROM2SHORT(0, max
  1802.  
  1803.  /* Scrollbar redraw macros */
  1804.  #define UpdateOn(c, hsb)        if (!(++c)) WinEnableWindowUpdate(hsb, TRUE)
  1805.  #define UpdateOff(c, hsb)        if (!(c--)) WinEnableWindowUpdate(hsb, FALSE
  1806.  #define        UpdateFrame(sb)        \
  1807.          WinSendMsg(hWndFrame, WM_UPDATEFRAME, MPFROMLONG(sb), 0L)
  1808.  
  1809.  /* Scrolling Macros */
  1810.  ClearScreen()        ScrollUp(-1)        /* Scroll up an "infinite" # lines *
  1811.  #define ScrollDown(n)        VioScrollDn(0, 0, -1, -1, n, Blank, hVPS)
  1812.  #define ScrollUp(n)        VioScrollUp(0, 0, -1, -1, n, Blank, hVPS)
  1813.  
  1814.  /* RectL -> SWP conversion macros */
  1815.  #define        lcx(r)                ((r.xRight - r.xLeft) + 1)
  1816.  #define        lcy(r)                ((r.yTop - r.yBottom) + 1)
  1817.  
  1818.  /* Miscellaneous macros */
  1819.  #define Blast(l, x, y)        VioWrtCharStr(l, Min((SHORT) strlen(l), cxChScr
  1820.  #define CalcChars(sPg, sCh) \
  1821.      ((sCh) ? (Max(((sPg) / (sCh)), 0)) : 0)
  1822.  #define        SetCellSize(h,w) VioSetDeviceCellSize(h, w, hVPS)
  1823.  #define        Value(value)        WinQuerySysValue(HWND_DESKTOP, value)
  1824.  /*
  1825.      File-Local Variables
  1826.  */
  1827.  HDC        hDC;                /* Device Context */
  1828.  HVPS        hVPS;                /* Virtual PS */
  1829.  int        iTopLine;        /* PS Line of window corner */
  1830.  int        iCurCol;         /* Current column of window corner */
  1831.  int        cxChPage;        /* Width and height of our window, in characters
  1832.  int        cyChPage;
  1833.  int        iMaxHorz;        /* Scroll bar upper bounds */
  1834.  int        iMaxVert;
  1835.  BOOL        fNeedHorz;        /* Do we need the scroll bars or not? */
  1836.  BOOL        fNeedVert;
  1837.  HWND        hWndHorzSB;        /* Window handles of ScrollBar windows */
  1838.  HWND        hWndVertSB;
  1839.  extern        HWND        hWndFrame;        /* Client, frame windows */
  1840.  extern        HWND        hWndClient;
  1841.  PFNWP        pfnOldClient;        /* Old Client Window Procedure pointer */
  1842.  PFNWP        pfnOldFrame;        /* Old Frame  Window Procedure pointer */
  1843.  SHORT        cyChPS;                /* Number of rows in AVIO PS */
  1844.  SHORT        cxChPS;                /* Number of cols in AVIO PS */
  1845.  SHORT        cyChScreen;                /* Number of rows in display space */
  1846.  SHORT        cxChScreen;                /* Number of cols in display space */
  1847.  PFNQL        pfnQueryLine;
  1848.  /*
  1849.      Measurements used to help make the window look nice
  1850.  */
  1851.  LONG        cxConstant, cyConstant;                        /* Miscellaneous f
  1852.  int        cxMaxFrame, cyMaxFrame;                        /* Maximum frame wi
  1853.  LONG        lChWidth,   lChHeight;
  1854.  SHORT        cxMaxClient, cyMaxClient;                /* Client area bounds
  1855.  BOOL        fCreatedPS;                                /* AVIO PS created */
  1856.  int        cHUpdate = -1;                                /* Keep track of upd
  1857.  int        cVUpdate = -1;
  1858.  /*
  1859.     Local prototypes
  1860.  */
  1861.  void FixScroll(BOOL, BOOL, HWND, ULONG, int *, int, int *);
  1862.  void UpdateScrollBars(RECTL);
  1863.  void Refresh(void);
  1864.  void Update(USHORT, USHORT, USHORT);
  1865.  /*
  1866.      The actual routines
  1867.  */
  1868.  void AvioInit(PLBINFO plbi) {
  1869.  /*
  1870.      Initialize Presentation Space, Device Context, Scroll Bars
  1871.  */
  1872.      VIOCURSORINFO vci;
  1873.      /*
  1874.          Initialize the line buffer info
  1875.      */
  1876.      cyChScreen        = plbi->sRows;
  1877.      cxChScreen        = plbi->sCols;
  1878.      cyChPS        = plbi->sPSrows;
  1879.      cxChPS        = plbi->sPScols;
  1880.      pfnQueryLine = plbi->pfnQL;
  1881.      /*
  1882.          One Time Initializations...
  1883.      */
  1884.      if (!fCreatedPS) {
  1885.          /*
  1886.             Create the AVIO Presentation Space, with one attribute byte
  1887.          */
  1888.          hDC = WinOpenWindowDC(hWndClient);        /* Open the device context
  1889.          VioCreatePS(&hVPS, cyChPS, cxChPS + 1, 0, 1, 0);
  1890.          VioAssociate(hDC, hVPS);                /* Link the PS with the DC */
  1891.          /*
  1892.              Turn off the cursor (set invisible attribute)
  1893.          */
  1894.          VioGetCurType(&vci, hVPS);
  1895.          vci.attr = -1;
  1896.          VioSetCurType(&vci, hVPS);
  1897.          /*
  1898.              Measure the frame components
  1899.          */
  1900.          cxConstant = 0;
  1901.          cyConstant = Value(SV_CYTITLEBAR) + Value(SV_CYMENU);
  1902.          /*
  1903.              Snag scroll bar info
  1904.          */
  1905.          hWndHorzSB        = WinWindowFromID(hWndFrame,  FID_HORZSCROLL);
  1906.          hWndVertSB        = WinWindowFromID(hWndFrame,  FID_VERTSCROLL);
  1907.          fNeedHorz        = fNeedVert        = TRUE;
  1908.          /*
  1909.              Setup the Client and Frame routines
  1910.          */
  1911.          pfnOldFrame        = WinSubclassWindow(hWndFrame,  AvioFrameWndProc);
  1912.          pfnOldClient        = WinSubclassWindow(hWndClient, AvioClientWndProc
  1913.          fCreatedPS        = TRUE;
  1914.      }
  1915.      /*
  1916.          Repaint the screen
  1917.      */
  1918.      iTopLine = iCurCol = 0;
  1919.      AvioStartup(plbi->fLargeFont);
  1920.  }
  1921.  
  1922.  void AvioStartup(BOOL fLargeFont) {
  1923.  /*
  1924.      Clear the screen, set the font, redraw the area
  1925.  */
  1926.      RECTL rclFrame;
  1927.  
  1928.      ClearScreen();
  1929.      AvioLargeFont(fLargeFont);
  1930.      WinQueryWindowRect(hWndFrame, &rclFrame);
  1931.      UpdateScrollBars(rclFrame);
  1932.      Update(0, cyChPS, 0);
  1933.  }
  1934.  
  1935.  void AvioScroll(USHORT SB_Command, USHORT Position, BOOL Horizontal) {
  1936.  /*
  1937.      Process the scroll bar messages
  1938.  
  1939.      These routines are symmetric; in fact, SB_LINELEFT = SB_LINEUP, etc...
  1940.      so one might note that this could be condensed.  It's left expanded for
  1941.      speed and clarity.  The scrollbar values are bounded to stay inside
  1942.      the Presentation Space.
  1943.  */
  1944.      if (Horizontal) {  /* Horizontal Scroll Bar */
  1945.          switch (SB_Command) {
  1946.              case SB_LINELEFT:
  1947.                  iCurCol = LowerBound(iCurCol, 1, 0); break;
  1948.              case SB_LINERIGHT:
  1949.                  iCurCol = UpperBound(iCurCol, 1, iMaxHorz); break;
  1950.              case SB_PAGELEFT:
  1951.                  iCurCol = LowerBound(iCurCol, cxChPage, 0); break;
  1952.              case SB_PAGERIGHT:
  1953.                  iCurCol = UpperBound(iCurCol, cxChPage, iMaxHorz); break;
  1954.              case SB_SLIDERTRACK:
  1955.                  iCurCol = (SHORT) Position;
  1956.              default: break;
  1957.          }
  1958.          if (SB_Command != SB_SLIDERTRACK)
  1959.              SetScroll(hWndHorzSB, iCurCol, iMaxHorz);
  1960.  
  1961.      } else { /* Vertical Scroll Bar */
  1962.          switch (SB_Command) {
  1963.              case SB_LINEUP:
  1964.                  iTopLine = LowerBound(iTopLine, 1, 0); break;
  1965.              case SB_LINEDOWN:
  1966.                  iTopLine = UpperBound(iTopLine, 1, iMaxVert); break;
  1967.              case SB_PAGEUP:
  1968.                  iTopLine = LowerBound(iTopLine, cyChPage, 0); break;
  1969.              case SB_PAGEDOWN:
  1970.                  iTopLine = UpperBound(iTopLine, cyChPage, iMaxVert);break;
  1971.              case SB_SLIDERTRACK:
  1972.                  iTopLine = (SHORT) Position;
  1973.              default: break;
  1974.          }
  1975.          if (SB_Command != SB_SLIDERTRACK)
  1976.              SetScroll(hWndVertSB, iTopLine, iMaxVert);
  1977.      }
  1978.      Refresh();
  1979.  }
  1980.  
  1981.  MRESULT AvioSize(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
  1982.  /*
  1983.      Do the default AVIO sizing, and kyfe a few values
  1984.  */
  1985.      RECTL rclFrame;
  1986.  
  1987.      if (!fCreatedPS) return 0L;
  1988.      /*
  1989.          Update the scroll bars, and the screen
  1990.      */
  1991.      WinQueryWindowRect(hWndFrame, &rclFrame);
  1992.      UpdateScrollBars(rclFrame);
  1993.      /*
  1994.          Now, do the normal AVIO processing
  1995.      */
  1996.      return WinDefAVioWindowProc(hWnd, msg, mp1, mp2);
  1997.  }
  1998.  
  1999.  void Update(USHORT usLineNum, USHORT usHowMany, USHORT usStartLine) {
  2000.  /*
  2001.      Updates N lines starting from START line on screen.
  2002.      Starts at saved line LINENUM.
  2003.  */
  2004.      USHORT        i;                                /* Loop index variable */
  2005.      USHORT        usWhichLine = usLineNum;        /* Line number to be querie
  2006.      char        *szLine;
  2007.  
  2008.      for (i = usStartLine; i < (usStartLine + usHowMany); i++) {
  2009.          szLine = (*pfnQueryLine)(usWhichLine++);        /* Get the line */
  2010.          if (szLine) Blast(szLine, i, 0);                /* Print it out */
  2011.      }
  2012.  }
  2013.  
  2014.  void Refresh(void) {
  2015.  /*
  2016.      Do the origin shifting and screen updating
  2017.  */
  2018.      SHORT  Delta;
  2019.      int static iOldTopLine = 0;
  2020.  
  2021.      VioSetOrg(0, iCurCol, hVPS); /* Get the free AVIO horizontal shift */
  2022.      Delta = iTopLine - iOldTopLine; /* Compute vertical shift */
  2023.      if (Abs(Delta) < cyChPS) {
  2024.          if (Delta < 0) {         /* Scroll Up -- make Delta positive*/
  2025.              ScrollDown(-Delta);
  2026.              Update(iTopLine, -Delta, 0);
  2027.          } else {                /* Scroll Down by Delta */
  2028.              ScrollUp(Delta);
  2029.              Update(iTopLine + cyChPS - Delta, Delta, cyChPS - Delta);
  2030.          }
  2031.      } else AvioRedraw();        /* Redo the entire screen */
  2032.      iOldTopLine = iTopLine;
  2033.  }
  2034.  
  2035.  void AvioClose(void) {
  2036.  /*
  2037.      Termination routines
  2038.  */
  2039.      /*
  2040.          Destroy the Presentation Space
  2041.      */
  2042.      VioAssociate(NULL, hVPS);
  2043.      VioDestroyPS(hVPS);
  2044.      fCreatedPS = FALSE;
  2045.  }
  2046.  
  2047.  void AvioPaint(HWND hWnd) {
  2048.  /*
  2049.      Paint the AVIO presentation space by telling it to show itself.
  2050.      A possible optimization here is to repaint only the update region.
  2051.  */
  2052.      static HPS         hPS;
  2053.      static RECTL RectL;
  2054.  
  2055.      hPS = WinBeginPaint(hWnd, (HPS) NULL, &RectL);
  2056.      VioShowPS(cyChPS, cxChPS, 0, hVPS);
  2057.      WinEndPaint(hPS);
  2058.  }
  2059.  
  2060.  MRESULT AvioMinMax(PSWP pSWP) {
  2061.  /*
  2062.      Handle WM_MINMAX messages, to make sure frame doesn't get too big
  2063.  */
  2064.      if (pSWP->fs & (SWP_MAXIMIZE | SWP_RESTORE)) {
  2065.          if (pSWP->fs & SWP_MAXIMIZE) {
  2066.              /*
  2067.                  Save cx, cy values for later origin displacement
  2068.              */
  2069.              int Oldcx = pSWP->cx;
  2070.              int Oldcy = pSWP->cy;
  2071.              /*
  2072.                  Displace, and change to maximum size
  2073.              */
  2074.              pSWP->x += (Oldcx -
  2075.                  (pSWP->cx = cxMaxFrame + (int) (Value(SV_CXSIZEBORDER) << 1))
  2076.              pSWP->y += (Oldcy -
  2077.                  (pSWP->cy = cyMaxFrame + (int) (Value(SV_CYSIZEBORDER) << 1))
  2078.          }
  2079.          /*
  2080.              Now, fix the scroll bars
  2081.          */
  2082.          AvioAdjustFramePos(pSWP);
  2083.          return (MRESULT) TRUE;
  2084.      }
  2085.      return FALSE;
  2086.  }
  2087.  
  2088.  void AvioClear(void) { ClearScreen(); }
  2089.  
  2090.  void AvioAdjustFramePos(PSWP pSWP) {
  2091.  /*
  2092.      Trap WM_ADJUSTWINDOWPOS messages to the frame with this routine.
  2093.      Keep the window sized right, and control scrollbar visibility.
  2094.  */
  2095.      RECTL rclFrame;
  2096.  
  2097.      if (!(pSWP->cx && pSWP->cy)) return;         /* Null area... */
  2098.      if (pSWP->fs & SWP_MINIMIZE) return;        /* Iconic... */
  2099.      /*
  2100.          Make sure the dimensions are in range
  2101.      */
  2102.      pSWP->cx = Min(pSWP->cx, (cxMaxFrame + (SHORT)(Value(SV_CXSIZEBORDER)<<1)
  2103.      pSWP->cy = Min(pSWP->cy, (cyMaxFrame + (SHORT)(Value(SV_CYSIZEBORDER)<<1)
  2104.      /*
  2105.          Update the scroll bars
  2106.      */
  2107.      rclFrame.xLeft        = (LONG) pSWP->x;
  2108.      rclFrame.xRight        = (LONG) (pSWP->x + pSWP->cx - 1);
  2109.      rclFrame.yBottom        = (LONG) pSWP->y;
  2110.      rclFrame.yTop        = (LONG) (pSWP->y + pSWP->cy - 1);
  2111.      UpdateScrollBars(rclFrame);
  2112.  
  2113.      return;
  2114.  }
  2115.  
  2116.  void AvioTrackFrame(HWND hWnd, MPARAM mpTrackFlags) {
  2117.  /*
  2118.      Takes action on WM_TRACKFRAME message
  2119.  */
  2120.      static TRACKINFO tiTrackInfo;
  2121.      /*
  2122.          Get the tracking information in the TrackInfo structure
  2123.      */
  2124.      WinSendMsg(hWnd, WM_QUERYTRACKINFO, mpTrackFlags, &tiTrackInfo);
  2125.      WinTrackRect(hWnd, NULL, &tiTrackInfo);
  2126.  }
  2127.  
  2128.  void AvioQueryTrackInfo(PTRACKINFO pTI) {
  2129.  /*
  2130.      Routine which processes WM_QUERYTRACKINFO messages to the frame.
  2131.      Call this routine after the default one to change various parameters.
  2132.  
  2133.      Note:  In reality, since we have a menu bar, we should make the
  2134.      minimum width of the window something such that it does not "fold."
  2135.  */
  2136.      BOOL fMove;
  2137.      /*
  2138.          Get the grid set up for byte alignment (unless moving)
  2139.  
  2140.          cxGrid is set to half character width so that arrow keys
  2141.          will function when sizing (they try to size by half a
  2142.          character)
  2143.      */
  2144.      fMove = ((pTI->fs & TF_MOVE) == TF_MOVE);
  2145.      pTI->fs     |= TF_GRID;
  2146.      pTI->cxGrid  = (fMove) ? 1 : ((SHORT) lChWidth);
  2147.      pTI->cyGrid  = (fMove) ? 1 : ((SHORT) lChHeight);
  2148.      pTI->cxKeyboard        =        (SHORT) lChWidth;
  2149.      pTI->cyKeyboard        =        (SHORT) lChHeight;
  2150.      /*
  2151.          Bound the frame.
  2152.          Maximum:        Sizing Border, Scrollbars, Title, Menus, client regio
  2153.      */
  2154.      pTI->ptlMaxTrackSize.x = (LONG) (pTI->cxBorder << 1) + (LONG) cxMaxFrame;
  2155.      pTI->ptlMaxTrackSize.y = (LONG) (pTI->cyBorder << 1) + (LONG) cyMaxFrame;
  2156.  }
  2157.  
  2158.  void AvioRedraw(void) {
  2159.  /*
  2160.      Clear, then redraw the entire Presentation Space
  2161.  */
  2162.      ClearScreen();
  2163.      Update(iTopLine, cyChPS, 0);
  2164.  }
  2165.  
  2166.  MRESULT CALLBACK AvioClientWndProc
  2167.          (HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
  2168.  /*
  2169.       Window Procedure which traps messages to the Client area
  2170.  */
  2171.       switch (msg) {
  2172.            case WM_PAINT:                /* Paint the AVIO way! */
  2173.                  AvioPaint(hWnd);
  2174.                  break;
  2175.  
  2176.            case WM_SIZE:                        /* Size the AVIO way!  */
  2177.                  return AvioSize(hWnd, msg, mp1, mp2);
  2178.                  break;
  2179.  
  2180.            case WM_HSCROLL:
  2181.                  AvioScroll(HIUSHORT(mp2), LOUSHORT(mp2), TRUE);
  2182.                  break;
  2183.  
  2184.            case WM_VSCROLL:
  2185.                  AvioScroll(HIUSHORT(mp2), LOUSHORT(mp2), FALSE);
  2186.                  break;
  2187.  
  2188.            case WM_ERASEBACKGROUND:
  2189.                  break;
  2190.  
  2191.            case WM_TRACKFRAME:
  2192.                  AvioTrackFrame(hWnd, mp1);
  2193.                  break;
  2194.  
  2195.            case WM_MINMAXFRAME:                /* Limit Maximized window size
  2196.                  AvioMinMax((PSWP) mp1);
  2197.  
  2198.                  /* fall through */
  2199.  
  2200.            default: return (*pfnOldClient)(hWnd, msg, mp1, mp2);
  2201.       }
  2202.       return 0;
  2203.  }
  2204.  
  2205.  MRESULT CALLBACK AvioFrameWndProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM m
  2206.  /*
  2207.      Force the frame to stay small enough (no larger than the PS)
  2208.  */
  2209.  {
  2210.      BOOL rc;                /* Return code from WM_QUERYTRACKINFO */
  2211.  
  2212.      switch(msg) {
  2213.          case WM_ADJUSTWINDOWPOS:        /* Calculate scroll bar adjustments *
  2214.              AvioAdjustFramePos(mp1);
  2215.              break;
  2216.  
  2217.          case WM_QUERYTRACKINFO:                /* Get default, then process m
  2218.              rc = (BOOL) SHORT1FROMMR((*pfnOldFrame)(hWnd, msg, mp1, mp2));
  2219.              AvioQueryTrackInfo((PTRACKINFO) mp2);
  2220.              return (MRESULT) rc;
  2221.  
  2222.          default: break;
  2223.      }
  2224.      return (*pfnOldFrame)(hWnd, msg, mp1, mp2);
  2225.  }
  2226.  
  2227.  void UpdateScrollBars(RECTL rclClient) {
  2228.  /*
  2229.      This routine fixes up the scroll bars when the window is resized, or
  2230.      when the font size is changed.
  2231.  
  2232.      Parameters:        The dimensions of the frame window
  2233.      Result:        Updates the scrollbars, enabling/disabling as needed
  2234.  */
  2235.      BOOL    fNeededHorz = fNeedHorz;  /* Did we need the scrollbars then? */
  2236.      BOOL    fNeededVert = fNeedVert;
  2237.      /*
  2238.          Compute the client rectangle, without the scrollbars
  2239.      */
  2240.      WinCalcFrameRect(hWndFrame, &rclClient, TRUE);
  2241.      /*
  2242.          Compute page width -- do we need the horizontal scroll bar?
  2243.      */
  2244.      cxChPage         = (int) CalcChars(lcx(rclClient), lChWidth);
  2245.      fNeedHorz = ((iMaxHorz = Max(cxChScreen - cxChPage,  0)) > 0);
  2246.      /*
  2247.          Compute page height -- do we need the vertical scroll bar?
  2248.      */
  2249.      cyChPage         = (int) CalcChars(lcy(rclClient), lChHeight);
  2250.      fNeedVert = ((iMaxVert = Max(cyChScreen - cyChPage, 0)) > 0);
  2251.      /*
  2252.          Maintain scrollbar integrity
  2253.      */
  2254.      iCurCol        = Min(iCurCol, iMaxHorz);
  2255.      iTopLine        = Min(iTopLine, iMaxVert);
  2256.      /*
  2257.          Now, update the scrollbars as necessary
  2258.      */
  2259.      FixScroll(fNeededHorz, fNeedHorz, hWndHorzSB,
  2260.                FCF_HORZSCROLL, &iCurCol, iMaxHorz, &cHUpdate);
  2261.  
  2262.      FixScroll(fNeededVert, fNeedVert, hWndVertSB,
  2263.                FCF_VERTSCROLL, &iTopLine, iMaxVert, &cVUpdate);
  2264.      /*
  2265.          Now, update the screen to be visually consistent
  2266.      */
  2267.      Refresh();
  2268.  }
  2269.  
  2270.  void FixScroll(fNeeded, fNeed, hWnd, flScroll, piPos, iMax, pc)
  2271.  /*
  2272.      This routine makes the necessary scrollbar adjustments, and
  2273.      also enables/disables them.
  2274.  */
  2275.  BOOL        fNeeded;            /* Whether we used to need the scrollbar */
  2276.  BOOL        fNeed;                    /* Whether we need the scrollbar now */
  2277.  HWND        hWnd;                    /* Handle to the scrollbar window */
  2278.  ULONG        flScroll;            /* FCF_xxxxSCROLL flag (for the scrollbar)
  2279.  int        *piPos;             /* Current location of scrollbar thumb */
  2280.  int        iMax;                    /* New maximum for the scrollbar */
  2281.  int        *pc;                    /* Counter for WinEnableWindowUpdate recur
  2282.  {
  2283.      if (fNeed) {    /* Enable the scroll bar -- we didn't need it before */
  2284.          if (!fNeeded) {
  2285.              EnableSB(hWnd);
  2286.              UpdateOff((*pc), hWnd);
  2287.              UpdateFrame(flScroll);
  2288.              UpdateOn((*pc), hWnd);
  2289.          }
  2290.          SetScroll(hWnd, (*piPos) = Min((*piPos), iMax), iMax);
  2291.      } else {            /* Disable the scroll bar, we no longer need it */
  2292.          if (fNeeded) {
  2293.              DisableSB(hWnd);
  2294.              UpdateOff((*pc), hWnd);
  2295.              UpdateFrame(flScroll);
  2296.              UpdateOn((*pc), hWnd);
  2297.          }
  2298.      }
  2299.  }
  2300.  
  2301.  void AvioLargeFont(BOOL fLargeFont) {
  2302.      static BOOL fFirst = TRUE;                                    // Need to
  2303.      static LONG lSmallHt, lSmallWd, lLargeHt, lLargeWd;     // Font sizes
  2304.      SWP swp;
  2305.  
  2306.      if (fFirst) {
  2307.          /*
  2308.              The first time through, get the small and large font sizes
  2309.          */
  2310.          DevQueryCaps(hDC, CAPS_CHAR_HEIGHT,                1L, &lLargeHt);
  2311.          DevQueryCaps(hDC, CAPS_CHAR_WIDTH,                1L, &lLargeWd);
  2312.          DevQueryCaps(hDC, CAPS_SMALL_CHAR_HEIGHT,        1L, &lSmallHt);
  2313.          DevQueryCaps(hDC, CAPS_SMALL_CHAR_WIDTH,        1L, &lSmallWd);
  2314.          fFirst = FALSE;
  2315.      }
  2316.      /*
  2317.          Set the character size with VioSetDeviceCellSize
  2318.      */
  2319.      SetCellSize( (SHORT) (lChHeight = ((fLargeFont) ? lLargeHt : lSmallHt)),
  2320.                   (SHORT) (lChWidth  = ((fLargeFont) ? lLargeWd : lSmallWd)) )
  2321.      /*
  2322.          Compute maximum size of client area
  2323.      */
  2324.      cxMaxClient        = (cxChPS * (SHORT) lChWidth);
  2325.      cxMaxFrame        = cxMaxClient + (SHORT) cxConstant;
  2326.      cyMaxClient = (cyChPS * (SHORT) lChHeight);
  2327.      cyMaxFrame  = cyMaxClient + (SHORT) cyConstant;
  2328.      /*
  2329.          Send a WM_ADJUSTFRAMEPOS message
  2330.      */
  2331.      WinQueryWindowPos(hWndFrame, &swp);
  2332.      if (swp.fs & SWP_MAXIMIZE) {
  2333.          AvioMinMax(&swp);
  2334.          WinSetMultWindowPos(hWndFrame, &swp, 1);
  2335.      } else {
  2336.          swp.fs = SWP_ACTIVATE | SWP_MOVE | SWP_SHOW | SWP_SIZE;
  2337.          WinSetWindowPos(hWndFrame, NULL, swp.x, swp.y,
  2338.              Min(cxMaxFrame, swp.cx), Min(cyMaxFrame, swp.cy), swp.fs);
  2339.      }
  2340.      AvioAdjustFramePos(&swp);                /* Fix up the frame, scroll bars
  2341.      AvioPaint(hWndClient);                /* Repaint with new characters   */
  2342.  }
  2343.  
  2344.  
  2345.  AVIO.C
  2346.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\COMTALK\AVIO.C
  2347.  
  2348.  /*
  2349.          avio.c -- AVIO handling routines
  2350.          For a cleaner implementation, look at the BROWSE application.
  2351.  
  2352.          Implements scrollbars, sets up an AVIO Presentation Space
  2353.          Intrinsically linked with a circular queue routine
  2354.  
  2355.          Created by Microsoft Corporation, 1989
  2356.  */
  2357.  
  2358.  #define  INCL_AVIO
  2359.  #define         INCL_DEV
  2360.  #define  INCL_VIO
  2361.  #define         INCL_WIN
  2362.  #include <os2.h>
  2363.  #include "global.h"
  2364.  "circleq.h"        /* Get Circular Buffer routines */
  2365.  "avio.h"        /* Prototype our routines */
  2366.  <stdio.h>        /* Needed to open LOG file */
  2367.  /*
  2368.      Constants
  2369.  */
  2370.  AVIO_PS_ROWS        25        /* Dimensions of the AVIO PS */
  2371.  #define AVIO_PS_COLUMNS        MAXLINELEN
  2372.         CATTRBYTES        1        /* 1 or 3 attribute bytes/cell */
  2373.         DEFPAGEWIDTH        5        /* Default pagesizes */
  2374.  #define        DEFPAGEHEIGHT        5
  2375.  
  2376.  char        Blank[2] = { 0x20, 0x07 };
  2377.  
  2378.  /*
  2379.      Macros to make the code more readable
  2380.  */
  2381.  /* Upper and Lower Bound Calculations */
  2382.  #define        Abs(a)                (((a) > 0) ? (a) : (-(a)))
  2383.  #define LowerBound(pos, disp, lbound) Max(pos - disp, lbound)
  2384.  #define UpperBound(pos, disp, ubound) Min(pos + disp, ubound)
  2385.  
  2386.  /* Scroll Bar Abbreviations */
  2387.  
  2388.  #define        DisableSB(hSB)        WinSetParent(hSB,  HWND_OBJECT, FALSE)
  2389.  #define        EnableSB(hSB)        WinSetParent(hSB, hWndSBParent, FALSE)
  2390.  #define        HBarHeight()        (fNeedHorz ? lHSBHeight : 0L)
  2391.  #define        VBarWidth()        (fNeedVert ? lVSBWidth  : 0L)
  2392.  #define SetScroll(h, pos, max) \
  2393.      WinSendMsg(h, SBM_SETSCROLLBAR, MPFROM2SHORT(pos, 0), MPFROM2SHORT(0, max
  2394.  #define        UpdateFrame(sb)        \
  2395.      WinSendMsg(hWndSBParent, WM_UPDATEFRAME, MPFROMLONG(sb), 0L)
  2396.  #define        UpdateOff(w)        WinEnableWindowUpdate(w, FALSE)
  2397.  #define        UpdateOn(w)        WinEnableWindowUpdate(w, TRUE)
  2398.  
  2399.  /* Scrolling Macros */
  2400.  #define        ClearScreen()        ScrollUp(-1)
  2401.  #define ScrollDown(n)        VioScrollDn(0, 0, -1, -1, n, Blank, hVPS)
  2402.  #define        ScrollUp(n)        VioScrollUp(0, 0, -1, -1, n, Blank, hVPS)
  2403.  #define        SetCursor(x, y)        VioSetCurPos((USHORT) x, (USHORT) y, hV
  2404.  
  2405.  /* Miscellaneous */
  2406.  /*
  2407.      If partial ANSI emulation is desired, use:
  2408.          VioSetCurPos((USHORT) x, (USHORT) y, hVPS); \
  2409.          VioWrtTTY(l->szText, l->cch, hVPS)
  2410.  */
  2411.  #define Blast(l, x, y)        VioWrtCharStr(l->szText, l->cch, x, y, hVPS)
  2412.  /*
  2413.      Calculate the number of characters in a page
  2414.      For nicer behavior, you can do rounding here
  2415.  */
  2416.  #define CalcChars(pPg, pCh, default) \
  2417.          ((pCh) ? (Max((int) ((pPg) / ((SHORT) pCh)), 0)) : (default))
  2418.  #define        Value(value)        WinQuerySysValue(HWND_DESKTOP, value)
  2419.  /*
  2420.      File-Local Variables
  2421.  */
  2422.  HDC        hDC;                /* Device Context */
  2423.  HVPS        hVPS;                /* Virtual PS */
  2424.  int        iTopLine;        /* PS Line of window corner */
  2425.  int        iCurCol;         /* Current column of window corner */
  2426.  int        cchPgWidth;        /* Width and height of our window */
  2427.  int        cchPgHeight;
  2428.  int        cchMaxHorz;        /* Scroll bar upper bounds */
  2429.  int        cchMaxVert;
  2430.  BOOL        fNeedHorz;        /* Do we need the scroll bars or not? */
  2431.  BOOL        fNeedVert;
  2432.  HWND        hWndHScroll;        /* Window handles of ScrollBar windows */
  2433.  HWND        hWndVScroll;
  2434.  HWND        hWndSBParent;        /* Could mooch off the value in main(), but
  2435.  /*
  2436.      Measurements used to help make the window look nice
  2437.  */
  2438.  LONG        lChWidth,   lChHeight;                        /* Character size *
  2439.  LONG        lHSBHeight, lVSBWidth;                        /* Scrollbar measur
  2440.  LONG        lMiscWidth, lMiscHeight;                /* Border, titlebar, ...
  2441.  int        iMaxWidth,  iMaxHeight;                        /* Client area boun
  2442.  int        iMaxFrameWidth, iMaxFrameHeight;        /* Frame window bounds */
  2443.  BOOL        fCreated;                                /* AVIO PS created */
  2444.  int        rc;                                        /* Return code */
  2445.  VIOCURSORINFO vci;
  2446.  /*
  2447.     Local prototypes
  2448.  */
  2449.  void GetMeasurements(void);
  2450.  void Update(USHORT, USHORT, USHORT, BOOL);
  2451.  void Refresh(BOOL);
  2452.  void WantCursor(BOOL);
  2453.  void SetScrollPos(void);
  2454.  void SetScrollPosHorz(void);
  2455.  void SetScrollPosVert(void);
  2456.  /*
  2457.      The actual routines
  2458.  */
  2459.  void GetMeasurements(void) {
  2460.  /*
  2461.      Get display parameters
  2462.  */
  2463.      /*
  2464.          Scroll bar widths and heights
  2465.      */
  2466.      lHSBHeight        = Value(SV_CYHSCROLL);
  2467.      lVSBWidth        = Value(SV_CXVSCROLL);
  2468.      /*
  2469.          Non-PS widths and heights
  2470.      */
  2471.      lMiscHeight        = (Value(SV_CYSIZEBORDER) << 1)        /* A border on
  2472.                  + Value(SV_CYTITLEBAR)                /* The title bar...
  2473.                  + Value(SV_CYMENU)                /* ...and the menu bar   */
  2474.                  + Value(SV_CYBYTEALIGN);        /* ...and alignment         *
  2475.  
  2476.      lMiscWidth        = (Value(SV_CXSIZEBORDER) << 1);/* A border on each sid
  2477.      /*
  2478.          Height and width of characters
  2479.      */
  2480.      rc = DevQueryCaps(hDC, CAPS_CHAR_HEIGHT, 1L, &lChHeight);
  2481.      rc = DevQueryCaps(hDC, CAPS_CHAR_WIDTH,  1L, &lChWidth);
  2482.      /*
  2483.          Compute size of client and frame windows
  2484.      */
  2485.      iMaxWidth                = (AVIO_PS_COLUMNS        * (int) lChWidth);
  2486.      iMaxHeight                = (AVIO_PS_ROWS                * (int) lChHeigh
  2487.      iMaxFrameWidth        = (iMaxWidth                + (int) lMiscWidth);
  2488.      iMaxFrameHeight        = (iMaxHeight                + (int) lMiscHeight);
  2489.      /*
  2490.          Compute cursor attributes
  2491.      */
  2492.      vci.yStart        = (USHORT) 0;
  2493.      vci.cEnd        = (USHORT) lChHeight - 1;
  2494.      vci.cx        = 0;
  2495.  }
  2496.  
  2497.  void AvioInit(HWND hWndFrame, HWND hWndClient) {
  2498.  /*
  2499.      Initialize Presentation Space, Device Context, Scroll Bars
  2500.  */
  2501.      /*
  2502.          Create the AVIO Presentation Space
  2503.      */
  2504.      hDC = WinOpenWindowDC(hWndClient);
  2505.      VioCreatePS(&hVPS, AVIO_PS_ROWS, AVIO_PS_COLUMNS, 0, CATTRBYTES, 0);
  2506.      VioAssociate(hDC, hVPS);
  2507.      fCreated = TRUE;
  2508.      /*
  2509.          Turn on the cursor and home it
  2510.      */
  2511.      WantCursor(TRUE);
  2512.      SetCursor(0, 0);
  2513.      /*
  2514.          Snag scroll bar info
  2515.      */
  2516.      hWndHScroll  = WinWindowFromID(hWndFrame,  FID_HORZSCROLL);
  2517.      hWndVScroll  = WinWindowFromID(hWndFrame,  FID_VERTSCROLL);
  2518.      hWndSBParent = WinQueryWindow(hWndHScroll, QW_PARENT, FALSE);
  2519.      fNeedHorz         = fNeedVert  = TRUE;
  2520.      /*
  2521.          Get character height in pixels, etc...
  2522.      */
  2523.      GetMeasurements();
  2524.  }
  2525.  
  2526.  void AvioStartup(HWND hWndClient) {
  2527.      SWP swp;
  2528.      /*
  2529.          Initialize the queue
  2530.      */
  2531.      QueInit();
  2532.      /*
  2533.          Initialize the screen
  2534.      */
  2535.      ClearScreen();
  2536.      WinQueryWindowPos(hWndClient, &swp);
  2537.      AvioSize(hWndClient, WM_NULL, NULL, MPFROM2SHORT(swp.cx, swp.cy));
  2538.  }
  2539.  
  2540.  void AvioScroll(USHORT SB_Command, USHORT usPosition, BOOL fHorizontal) {
  2541.  /*
  2542.      Process the scroll bar messages
  2543.  
  2544.      These routines are symmetric; in fact, SB_LINELEFT = SB_LINEUP, etc...
  2545.      so one might note that this could be condensed.  It's left expanded for
  2546.      speed and clarity.  I bound the values each way so that we stay inside
  2547.      the AVIO presentation space.
  2548.  */
  2549.      if (fHorizontal) {  /* Horizontal Scroll Bar */
  2550.          switch (SB_Command) {
  2551.              case SB_LINELEFT:
  2552.                  iCurCol = LowerBound(iCurCol, 1, 0); break;
  2553.              case SB_LINERIGHT:
  2554.                  iCurCol = UpperBound(iCurCol, 1, cchMaxHorz); break;
  2555.              case SB_PAGELEFT:
  2556.                  iCurCol = LowerBound(iCurCol, cchPgWidth, 0); break;
  2557.              case SB_PAGERIGHT:
  2558.                  iCurCol = UpperBound(iCurCol, cchPgWidth, cchMaxHorz); break;
  2559.              case SB_SLIDERTRACK:
  2560.                  iCurCol = (SHORT) usPosition;
  2561.              default: break;
  2562.          }
  2563.          if (SB_Command != SB_SLIDERTRACK)
  2564.              SetScroll(hWndHScroll, iCurCol, cchMaxHorz);
  2565.  
  2566.      } else { /* Vertical Scroll Bar */
  2567.          switch (SB_Command) {
  2568.              case SB_LINEUP:
  2569.                  iTopLine = LowerBound(iTopLine, 1, 0); break;
  2570.              case SB_LINEDOWN:
  2571.                  iTopLine = UpperBound(iTopLine, 1, cchMaxVert); break;
  2572.              case SB_PAGEUP:
  2573.                  iTopLine = LowerBound(iTopLine, cchPgHeight, 0); break;
  2574.              case SB_PAGEDOWN:
  2575.                  iTopLine = UpperBound(iTopLine, cchPgHeight, cchMaxVert); bre
  2576.              case SB_SLIDERTRACK:
  2577.                  iTopLine = (SHORT) usPosition;
  2578.              default: break;
  2579.          }
  2580.          if (SB_Command != SB_SLIDERTRACK)
  2581.              SetScroll(hWndVScroll, iTopLine, cchMaxVert);
  2582.      }
  2583.      Refresh(FALSE);
  2584.  }
  2585.  
  2586.  MRESULT AvioSize(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
  2587.  /*
  2588.      Do the default AVIO sizing, and kyfe a few values
  2589.  */
  2590.      if (!fCreated) return 0L;
  2591.      /*
  2592.          Compute height and width of page in characters
  2593.  
  2594.          The scrollbars have already been subtracted out,
  2595.          since we are called by the client area.
  2596.      */
  2597.      cchPgHeight = CalcChars(SHORT2FROMMP(mp2), lChHeight, DEFPAGEHEIGHT);
  2598.      cchPgWidth  = CalcChars(SHORT1FROMMP(mp2), lChWidth,  DEFPAGEWIDTH);
  2599.      /*
  2600.          Adjust scrollbar maximums
  2601.      */
  2602.      cchMaxVert = Max(AVIO_PS_ROWS    - cchPgHeight, 0);
  2603.      cchMaxHorz = Max(AVIO_PS_COLUMNS -  cchPgWidth, 0);
  2604.      /*
  2605.          Maintain scrollbar integrity
  2606.      */
  2607.      fNeedHorz = (cchMaxHorz > 0);
  2608.      fNeedVert = (cchMaxVert > 0);
  2609.      SetScroll(hWndHScroll, iCurCol  = Min(iCurCol, cchMaxHorz), cchMaxHorz);
  2610.      SetScroll(hWndVScroll, iTopLine = Min(iTopLine,cchMaxVert), cchMaxVert);
  2611.      /*
  2612.          Do the Scroll Bar shifting
  2613.      */
  2614.      Refresh(FALSE);
  2615.      /*
  2616.          Now, do the normal AVIO processing
  2617.      */
  2618.      return WinDefAVioWindowProc(hWnd, msg, mp1, mp2);
  2619.  }
  2620.  
  2621.  void Update
  2622.      (USHORT usLineNum, USHORT usHowMany, USHORT usStartLine, BOOL fForced) {
  2623.  /*
  2624.      Updates usHowMany lines starting from usStartLine on screen.
  2625.      Starts at saved line usLineNum.  If fForced is set, all lines
  2626.      in range are displayed; otherwise it's lazy.
  2627.  */
  2628.      USHORT        i;                                /* Loop index */
  2629.      USHORT        usWhichLine = usLineNum;        /* Line to be queried */
  2630.      Line        l;                                /* Line to be output */
  2631.  
  2632.      for (i = usStartLine; i < (usStartLine + usHowMany); i++) {
  2633.          l = QueQuery(usWhichLine++);                /* Get the line */
  2634.          if (!l->fDrawn || fForced) {
  2635.              if (l->cch) Blast(l, i, 0);                /* Print it out */
  2636.              if (!l->fComplete) SetCursor(i, l->cch);
  2637.              l->fDrawn = TRUE;
  2638.          }
  2639.      }
  2640.  }
  2641.  
  2642.  void Refresh(BOOL fRedraw) {
  2643.  /*
  2644.      fRedraw forces full redraw if set
  2645.  */
  2646.      SHORT  sDelta;
  2647.      int static iOldTopLine = -AVIO_PS_ROWS;
  2648.  
  2649.      VioSetOrg(0, iCurCol, hVPS); /* Get the free AVIO horizontal shift */
  2650.      sDelta = iTopLine - iOldTopLine; /* Compute vertical shift */
  2651.      if ((Abs(sDelta) < AVIO_PS_ROWS) && !fRedraw) {
  2652.          if (sDelta < 0) {         /* Scroll Up -- make sDelta positive*/
  2653.              ScrollDown(-sDelta);
  2654.              Update(iTopLine, -sDelta, 0, TRUE);
  2655.          } else {                /* Scroll Down by sDelta */
  2656.              ScrollUp(sDelta);
  2657.              Update(iTopLine + cchPgHeight - sDelta, sDelta,
  2658.                                  cchPgHeight - sDelta, TRUE);
  2659.          }
  2660.      } else AvioRedraw();        /* Redo the entire screen */
  2661.      iOldTopLine = iTopLine;
  2662.  }
  2663.  
  2664.  void AvioClose (void) {
  2665.  /*
  2666.      Termination routines
  2667.  */
  2668.      /*
  2669.          Destroy the Presentation Space
  2670.      */
  2671.      VioAssociate(NULL, hVPS);
  2672.      VioDestroyPS(hVPS);
  2673.      fCreated = FALSE;
  2674.  }
  2675.  
  2676.  void AvioPaint(HWND hWnd) {
  2677.      static HPS   hPS;
  2678.      static RECTL rcl;
  2679.  
  2680.      hPS = WinBeginPaint(hWnd, NULL, &rcl);
  2681.      VioShowPS(AVIO_PS_ROWS, AVIO_PS_COLUMNS, 0, hVPS);
  2682.      WinEndPaint(hPS);
  2683.  }
  2684.  
  2685.  MRESULT AvioMinMax(PSWP pSWP) {
  2686.  /*
  2687.      Control Maximizing
  2688.  */
  2689.      if (pSWP->fs & (SWP_MAXIMIZE | SWP_RESTORE)) {
  2690.          if (pSWP->fs & SWP_MAXIMIZE) {
  2691.              /*
  2692.                  Save cx, cy values for later origin displacement
  2693.              */
  2694.              int iOldcx = pSWP->cx;
  2695.              int iOldcy = pSWP->cy;
  2696.              /*
  2697.                  Displace, and change to maximum size
  2698.              */
  2699.              pSWP->x += (iOldcx - (pSWP->cx = iMaxFrameWidth));
  2700.              pSWP->y += (iOldcy - (pSWP->cy = iMaxFrameHeight));
  2701.          }
  2702.          /*
  2703.              Now, fix the scroll bars
  2704.          */
  2705.          AvioAdjustFrame(pSWP);
  2706.          return (MRESULT) TRUE;
  2707.      }
  2708.      return FALSE;
  2709.  }
  2710.  
  2711.  void AvioClear(void) { ClearScreen(); }
  2712.  
  2713.  void AvioAdjustFrame(PSWP pSWP) {
  2714.  /*
  2715.      Trap WM_ADJUSTWINDOWPOS messages to the frame with this routine.
  2716.      Keep the window sized right, and control scrollbar visibility.
  2717.  */
  2718.      BOOL fNeededHorz = fNeedHorz;
  2719.      BOOL fNeededVert = fNeedVert;
  2720.  /*
  2721.      Do scrollbar enable/disable calculations (but don't update the screen)
  2722.  */
  2723.      if (pSWP->fs & SWP_MINIMIZE) fNeedHorz = fNeedVert = FALSE;
  2724.      if ((pSWP->cx * pSWP->cy) == 0) return;
  2725.      /*
  2726.          Do we need them?
  2727.      */
  2728.      fNeedVert = (pSWP->cy < (SHORT) (iMaxFrameHeight));
  2729.      fNeedHorz = (pSWP->cx < (SHORT) (iMaxFrameWidth  + VBarWidth()));
  2730.      fNeedVert = (pSWP->cy < (SHORT) (iMaxFrameHeight + HBarHeight()));
  2731.  /*
  2732.      Do width calculations to make sure we're staying small enough.
  2733.      The Tracking Rectangle shouldn't allow us to get too big.
  2734.  */
  2735.      /*
  2736.          Check if we're stretching too far
  2737.      */
  2738.      pSWP->cx = Min(pSWP->cx, iMaxFrameWidth  + (int) VBarWidth());
  2739.      pSWP->cy = Min(pSWP->cy, iMaxFrameHeight + (int) HBarHeight());
  2740.      /*
  2741.          ...if so, fix, then add them!
  2742.      */
  2743.      AvioSize(NULL, WM_NULL, NULL, MPFROM2SHORT(
  2744.          pSWP->cx - (int) (lMiscWidth + VBarWidth()),
  2745.          pSWP->cy - (int) (lMiscHeight + HBarHeight()) ));
  2746.  
  2747.      if (fNeedHorz) {
  2748.          if (!fNeededHorz) {
  2749.              EnableSB(hWndHScroll);
  2750.              UpdateOff(hWndHScroll);
  2751.              UpdateFrame(FCF_HORZSCROLL);
  2752.              UpdateOn(hWndHScroll);
  2753.          }
  2754.      } else {
  2755.          if (fNeededHorz) {
  2756.              DisableSB(hWndHScroll);
  2757.              UpdateOff(hWndHScroll);
  2758.              UpdateFrame(FCF_HORZSCROLL);
  2759.              UpdateOn(hWndHScroll);
  2760.          }
  2761.      }
  2762.      if (fNeedVert) {
  2763.          if (!fNeededVert) {
  2764.               EnableSB(hWndVScroll);
  2765.               UpdateOff(hWndVScroll);
  2766.               UpdateFrame(FCF_VERTSCROLL);
  2767.               UpdateOn(hWndVScroll);
  2768.          }
  2769.      } else {
  2770.          if (fNeededVert) {
  2771.               DisableSB(hWndVScroll);
  2772.               UpdateOff(hWndVScroll);
  2773.               UpdateFrame(FCF_VERTSCROLL);
  2774.               UpdateOn(hWndVScroll);
  2775.          }
  2776.      }
  2777.  }
  2778.  
  2779.  void AvioTrackFrame(HWND hWnd, MPARAM mpTrackFlags) {
  2780.  /*
  2781.      Takes action on WM_TRACKFRAME message
  2782.  */
  2783.      static TRACKINFO tiTrackInfo;
  2784.      /*
  2785.          Get the tracking information in the TrackInfo structure
  2786.      */
  2787.      WinSendMsg(hWnd, WM_QUERYTRACKINFO, mpTrackFlags, &tiTrackInfo);
  2788.      WinTrackRect(hWnd, NULL, &tiTrackInfo);
  2789.  }
  2790.  
  2791.  void AvioQueryTrackInfo(PTRACKINFO pTI) {
  2792.  /*
  2793.      Forces the frame to be byte aligned and bounded
  2794.  */
  2795.      BOOL fMove;
  2796.      /*
  2797.          Get the grid set up for byte alignment
  2798.  
  2799.          Set cxGrid to half a character width, because sizing
  2800.          from the keyboard tries to move by half characters.
  2801.          Also, make sure we can move the window freely.
  2802.      */
  2803.      fMove = ((pTI->fs & TF_MOVE) == TF_MOVE);
  2804.      pTI->fs     |= TF_GRID;
  2805.      pTI->cxGrid  = (fMove) ? 1 : ((SHORT) lChWidth);
  2806.      pTI->cyGrid  = (fMove) ? 1 : ((SHORT) lChHeight);
  2807.      pTI->cxKeyboard = (SHORT) lChWidth;
  2808.      pTI->cyKeyboard = (SHORT) lChHeight;
  2809.      /*
  2810.          Bound the frame now
  2811.      */
  2812.      pTI->ptlMinTrackSize.x = (pTI->cxBorder << 1) + lMiscWidth;
  2813.      pTI->ptlMinTrackSize.y = (pTI->cyBorder << 1) + lMiscHeight;
  2814.      pTI->ptlMaxTrackSize.x = iMaxFrameWidth  + lVSBWidth +  (pTI->cxBorder <<
  2815.      pTI->ptlMaxTrackSize.y = iMaxFrameHeight + lHSBHeight + (pTI->cyBorder <<
  2816.  }
  2817.  
  2818.  BOOL AvioUpdateLines(BOOL fPage, BOOL *fPaging) {
  2819.  /*
  2820.      Update the display
  2821.  */
  2822.      int        cLines;
  2823.  
  2824.      cLines = QueUpdateHead(AVIO_PS_ROWS, fPage, *fPaging);
  2825.      if (cLines == AVIO_PS_ROWS) *fPaging = TRUE;
  2826.      if (cLines > 0) {
  2827.          ScrollUp(cLines);
  2828.          Update(iTopLine + AVIO_PS_ROWS - cLines, cLines,
  2829.                          AVIO_PS_ROWS - cLines, TRUE);
  2830.      }
  2831.      Update(iTopLine, cchPgHeight, 0, FALSE);
  2832.      return TRUE;
  2833.  }
  2834.  
  2835.  void AvioRedraw(void) {
  2836.  /*
  2837.      Clear, then redraw the entire Presentation Space
  2838.  */
  2839.      ClearScreen();
  2840.      Update(iTopLine, cchPgHeight, 0, TRUE);
  2841.  }
  2842.  
  2843.  void WantCursor(BOOL fYes) {
  2844.  /*
  2845.      Do the underscore cursor
  2846.  */
  2847.      vci.attr        = (USHORT) (fYes ? 0 : -1);
  2848.      vci.yStart        = 0;
  2849.      vci.cEnd        = (USHORT) lChHeight - 1;
  2850.      vci.cx        = 0;
  2851.      VioSetCurType(&vci, hVPS);
  2852.  }
  2853.  
  2854.  void AvioPageUp(void) {
  2855.  /*
  2856.      Execute the Page Up instruction
  2857.  */
  2858.      int cLines;
  2859.  
  2860.      cLines = QuePageUp(AVIO_PS_ROWS);
  2861.      ScrollDown(cLines);
  2862.      Update(iTopLine, cLines, 0, TRUE);
  2863.  }
  2864.  
  2865.  
  2866.  
  2867.  BIGBEN.C
  2868.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BIGBEN\BIGBEN.C
  2869.  
  2870.  /*
  2871.   * This example uses a few of the many VIO calls.
  2872.   *
  2873.   * This example puts the time on the screen in large numbers.
  2874.   *
  2875.   * Created by Microsoft Corp. 1986
  2876.   */
  2877.  
  2878.  #include <os2def.h>
  2879.  #define INCL_DOSPROCESS
  2880.  #define INCL_DOSDATETIME
  2881.  #include <bsedos.h>
  2882.  #define INCL_SUB
  2883.  #include <bsesub.h>
  2884.  #include <stdio.h>
  2885.  
  2886.  #define        CHAR_WIDTH        8
  2887.  #define        CHAR_HEIGHT        7
  2888.  
  2889.         CLOCK_ROW        10        /* row to start the clock */
  2890.         TOTAL_COLMS        80        /* screen size in colms */
  2891.         TOTAL_ROWS        24        /* screen size in rows */
  2892.  
  2893.  
  2894.  char        BigChars[10][CHAR_HEIGHT][CHAR_WIDTH] = {
  2895.  
  2896.  {
  2897.          "   00  ",
  2898.          "  0  0 ",
  2899.          " 0    0",
  2900.          " 0    0",
  2901.          " 0    0",
  2902.          "  0  0 ",
  2903.          "   00  "
  2904.  },
  2905.  {
  2906.          "   1   ",
  2907.          "   1   ",
  2908.          "   1   ",
  2909.          "   1   ",
  2910.          "   1   ",
  2911.          "   1   ",
  2912.          "   1   "
  2913.  },
  2914.  {
  2915.          "  2222 ",
  2916.          " 2    2",
  2917.          "      2",
  2918.          "     2 ",
  2919.          "   2   ",
  2920.          "  2    ",
  2921.          " 222222"
  2922.  },
  2923.  {
  2924.          " 33333 ",
  2925.          "      3",
  2926.          "      3",
  2927.          "   333 ",
  2928.          "      3",
  2929.          "      3",
  2930.          " 33333 "
  2931.  },
  2932.  {
  2933.          "    44 ",
  2934.          "   4 4 ",
  2935.          "  4  4 ",
  2936.          " 4   4 ",
  2937.          " 444444",
  2938.          "     4 ",
  2939.          "     4 "
  2940.  },
  2941.  {
  2942.          " 555555",
  2943.          " 5     ",
  2944.          " 55555 ",
  2945.          "      5",
  2946.          "      5",
  2947.          " 5    5",
  2948.          "  5555 "
  2949.  },
  2950.  {
  2951.          "    6  ",
  2952.          "   6   ",
  2953.          "  6    ",
  2954.          "  6666 ",
  2955.          " 6    6",
  2956.          " 6    6",
  2957.          "  6666 "
  2958.  },
  2959.  {
  2960.          " 777777",
  2961.          "      7",
  2962.          "     7 ",
  2963.          "    7  ",
  2964.          "   7   ",
  2965.          "  7    ",
  2966.          " 7     "
  2967.  },
  2968.  {
  2969.          "  8888 ",
  2970.          " 8    8",
  2971.          " 8    8",
  2972.          "  8888 ",
  2973.          " 8    8",
  2974.          " 8    8",
  2975.          "  8888 "
  2976.  },
  2977.  {
  2978.          "  9999 ",
  2979.          " 9    9",
  2980.          " 9    9",
  2981.          "  9999 ",
  2982.          "    9  ",
  2983.          "   9   ",
  2984.          "  9    "
  2985.  }
  2986.  };
  2987.  
  2988.  
  2989.  main(argc, argv)
  2990.          int        argc;
  2991.          char        *argv[];
  2992.  {
  2993.          unsigned        rc;        /* return code */
  2994.          DATETIME Now;         /* time struct for DosGetDateTime */
  2995.  
  2996.          /* clear the screen */
  2997.  
  2998.          VioWrtNCell( " \07", TOTAL_ROWS * TOTAL_COLMS, 0, 0, 0 );
  2999.  
  3000.          /* paint separators between hours and minutes, and minutes and second
  3001.  
  3002.          VioWrtNCell( "|\07", 1, (CLOCK_ROW + 2), 27, 0 );
  3003.          VioWrtNCell( "|\07", 1, (CLOCK_ROW + 5), 27, 0 );
  3004.          VioWrtNCell( "|\07", 1, (CLOCK_ROW + 2), 52, 0 );
  3005.          VioWrtNCell( "|\07", 1, (CLOCK_ROW + 5), 52, 0 );
  3006.  
  3007.          for (;;) {
  3008.  
  3009.              /* get the system time */
  3010.  
  3011.              if (rc = DosGetDateTime( &Now))  {
  3012.  
  3013.                  printf("DosGetDateTime failed, error: %d\n", rc);
  3014.                  DosExit(EXIT_PROCESS, 0);
  3015.              }
  3016.  
  3017.              /* write the digits out to the screen */
  3018.  
  3019.              LoadNumber(Now.hours / 10, 5, CLOCK_ROW);
  3020.              LoadNumber(Now.hours % 10, 15, CLOCK_ROW);
  3021.              LoadNumber(Now.minutes / 10, 30, CLOCK_ROW);
  3022.              LoadNumber(Now.minutes % 10, 40, CLOCK_ROW);
  3023.              LoadNumber(Now.seconds / 10, 55, CLOCK_ROW);
  3024.              LoadNumber(Now.seconds % 10, 65, CLOCK_ROW);
  3025.  
  3026.              DosSleep(900L);
  3027.          }
  3028.  }
  3029.  
  3030.  
  3031.  /* display the digit at the given coordinates */
  3032.  
  3033.  LoadNumber( dig, x, y )
  3034.          unsigned        dig;
  3035.          unsigned        x;
  3036.          unsigned        y;
  3037.  {
  3038.          int        i;
  3039.  
  3040.          /* write a list of char strings to make up a display number */
  3041.  
  3042.          for (i=0; (i < CHAR_HEIGHT); i++)
  3043.  
  3044.              /* write a character string starting from the coordinates */
  3045.  
  3046.              VioWrtCharStr( BigChars[dig][i], CHAR_WIDTH, y++, x, 0);
  3047.  }
  3048.  
  3049.  
  3050.  BIO.C
  3051.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BIO\BIO.C
  3052.  
  3053.  /*  Biorhythm - Utility to compute personal biorhythm charts.
  3054.  *
  3055.  *   Created by Microsoft Corp., 1989
  3056.  *
  3057.  *   Purpose:
  3058.  *       Program entry point, initialization and GetMessage loop.
  3059.  *
  3060.  *   Arguments:
  3061.  *       None
  3062.  *
  3063.  *   Globals (modified):
  3064.  *       hAB           - Handle to the Anchor Block
  3065.  *       hMsgQ         - Handle to the application's message queue
  3066.  *       hwndAppFrame  - Window handle of parent window's frame
  3067.  *       hwndKidFrame  - Window handle of parent window's frame
  3068.  *       hwndApp       - Window handle of parent window's client area
  3069.  *       hwndKid       - Window handle of child window's client area
  3070.  *       szAppName[10] - RC file program name (Biorhythm).
  3071.  *       szKidName[10] - RC file child window name (Legend).
  3072.  *
  3073.  *   Globals (referenced):
  3074.  *       tmFontInfo    - Text Metric structure defined during WM_CREATE
  3075.  *
  3076.  *   Description:
  3077.  *       The theory of biorhythms states that life consists of three cycles,
  3078.  *       physical, emotional and intellectual of 23, 28 and 33 days,
  3079.  *       respectively.  The cycles each begin on the date of birth.
  3080.  *
  3081.  *   Limits:
  3082.  *       The intended use of this program is for the 20th and 21st centuries.
  3083.  *       The calculations of biorhythms will not be accurate outside of this
  3084.  *       range due to formulae used to compute days between dates.
  3085.  *
  3086.  */
  3087.  
  3088.  #define INCL_WIN
  3089.  #include <os2.h>
  3090.  
  3091.  #include <stddef.h>
  3092.  
  3093.  #include "bio.h"
  3094.  
  3095.  /* Write-once global variables */
  3096.  HAB     hAB;
  3097.  HMQ     hMsgQ;
  3098.  HWND    hwndApp, hwndKid;
  3099.  HWND    hwndAppFrame, hwndKidFrame;
  3100.  char    szAppName[10];
  3101.  char    szKidName[10];
  3102.  ULONG        AppCtlData = FCF_STANDARD | FCF_VERTSCROLL | FCF_NOBYTEALIGN & ~
  3103.  ULONG        KidCtlData = FCF_TITLEBAR;
  3104.  PFNWP        OldFrameWndProc;
  3105.  
  3106.  /* Read-only global variables */
  3107.  extern  FONTMETRICS     tmFontInfo;
  3108.  extern        SHORT                cxLegendField;
  3109.  extern        SHORT                cxDateField;
  3110.  
  3111.  SHORT cdecl main(  )
  3112.  {
  3113.      QMSG        qMsg;
  3114.      SHORT       dx, dy, x, y;
  3115.      SHORT        cxSizeBorder;
  3116.      SHORT        cySizeBorder;
  3117.      SHORT        cxBorder;
  3118.      SHORT        cyBorder;
  3119.  
  3120.      /* Standard initialization.  Get anchor block and message queue. */
  3121.      hAB   = WinInitialize(0);
  3122.      hMsgQ = WinCreateMsgQueue( hAB, 0 );
  3123.  
  3124.      /* Get string constants for parent and child window registration
  3125.         and creation from resource string table. */
  3126.      WinLoadString( hAB, (HMODULE) NULL, IDS_APPNAME, sizeof(szAppName), szApp
  3127.      WinLoadString( hAB, (HMODULE) NULL, IDS_KIDNAME, sizeof(szKidName), szKid
  3128.  
  3129.      /* Register parent window.  Terminate if error. */
  3130.      if ( !WinRegisterClass( hAB, szAppName, BioWndProc,
  3131.              CS_CLIPCHILDREN | CS_SIZEREDRAW, 0 ) )
  3132.          return( FALSE );
  3133.  
  3134.      /* Register child window.  Terminate if error. */
  3135.      if ( !WinRegisterClass( hAB, szKidName, KidWndProc, 0, 0 ) )
  3136.          return( FALSE );
  3137.  
  3138.      /* Create a parent window of class szAppName */
  3139.      hwndAppFrame = WinCreateStdWindow(
  3140.          HWND_DESKTOP,
  3141.          0L,
  3142.          &AppCtlData,
  3143.          szAppName,
  3144.          NULL,
  3145.          0L,
  3146.          (HMODULE) NULL,
  3147.          ID_BIO,
  3148.          (HWND FAR *)&hwndApp
  3149.          );
  3150.  
  3151.      /* Create a child window of class KidClass */
  3152.      hwndKidFrame = WinCreateStdWindow(
  3153.          hwndApp,
  3154.          FS_BORDER,
  3155.          &KidCtlData,
  3156.          szKidName,
  3157.          szKidName,
  3158.          0L,
  3159.          (HMODULE) NULL,
  3160.          0,
  3161.          (HWND FAR *)&hwndKid
  3162.          );
  3163.  
  3164.      /* Subclass frame so that minimum window size can be controled */
  3165.      OldFrameWndProc = WinSubclassWindow( hwndAppFrame, FrameWndProc );
  3166.  
  3167.      /* Get the size of the screen and border.  Used to place and size window
  3168.      cxSizeBorder =  (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CXSIZEBORDER );
  3169.      cySizeBorder =  (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CYSIZEBORDER );
  3170.      cxBorder         =  (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CXBORDER );
  3171.      cyBorder         =  (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CYBORDER );
  3172.      x                 =  (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN )
  3173.      y                 =  (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN )
  3174.  
  3175.      /* Calculate width and height of child window.  Must be able to
  3176.         display three lines and wide enough for text and corresponding colored
  3177.         line.  Must take into account titlebar and border vertical sizes. */
  3178.      dx = cxLegendField * 2;
  3179.      dy = (SHORT)(tmFontInfo.lMaxBaselineExt*3 +
  3180.           WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) +
  3181.           WinQuerySysValue( HWND_DESKTOP, SV_CYBORDER ) * 2);
  3182.  
  3183.      /* Place and size parent and child windows, then make them visible.
  3184.         WinCreateStdWindow does not include position and size arguments.
  3185.         Parent window is thin, but full screen high.  Child window is placed
  3186.         10 pixels over and up from the parent window's lower left corner. */
  3187.      WinSetWindowPos( hwndAppFrame, NULL,
  3188.                       x-(3*cxDateField)+cxSizeBorder,
  3189.                       -cySizeBorder,
  3190.                       (3*cxDateField),
  3191.                       y+2*cySizeBorder,
  3192.                       SWP_MOVE | SWP_SIZE | SWP_ACTIVATE | SWP_SHOW );
  3193.      WinSetWindowPos( hwndKidFrame, NULL, 10, 10, dx, dy,
  3194.                       SWP_MOVE | SWP_SIZE | SWP_ACTIVATE | SWP_SHOW );
  3195.  
  3196.      /* Get messages from application queue and dispatch them for processing *
  3197.      while( WinGetMsg( hAB, &qMsg, (HWND)NULL, 0, 0 ) )
  3198.      {
  3199.          WinDispatchMsg( hAB, &qMsg );
  3200.      }
  3201.  
  3202.      /* Clean up.  All child windows will be destoyed automatically */
  3203.      WinDestroyWindow( hwndAppFrame );
  3204.      WinDestroyMsgQueue( hMsgQ );
  3205.      WinTerminate( hAB );
  3206.  }
  3207.  
  3208.  
  3209.  BIOCMD.C
  3210.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BIO\BIOCMD.C
  3211.  
  3212.  /*  BioDlg() - Dialog Box routine.
  3213.  *
  3214.  *   Created by Microsoft Corporation, 1989
  3215.  *
  3216.  *   Purpose:
  3217.  *       Allow setting of birthdate and viewing date for biorhythm display.
  3218.  *
  3219.  *   Arguments:
  3220.  *       hDlg          - Handle of Dialog Box owning message
  3221.  *       message       - Message itself
  3222.  *       mp1           - Extra message-dependent info
  3223.  *       mp2           - Extra message-dependent info
  3224.  *
  3225.  *   Globals (modified):
  3226.  *       Born          - Birthdate in julian days.  Read from OS2.INI.
  3227.  *       SelectDay     - Current day being tracked, day is highlighted.
  3228.  *                        This is stored as # days from birthdate.
  3229.  *                        This is initialized to the current date in WM_CREATE
  3230.  *       Day           - Day number from date born which is top line being
  3231.  *                       displayed.  Initially three days before SelectDay.
  3232.  *       bBorn         - Boolean indicating whether valid birtdate entered or
  3233.  *                       defined in OS2.INI.  Nothing graphed until valid.
  3234.  *
  3235.  *   Globals (referenced):
  3236.  *       hAB           - Handle to the Anchor Block
  3237.  *       szAppName[]   - RC file program name (Biorhythm).
  3238.  *
  3239.  *   Description:
  3240.  *       Biorythm cycles start on the date of birth and the state of
  3241.  *       of these cycles may be viewed on the selected date.  A check
  3242.  *       box is provided to update (record) the birthdate in the WIN.INI
  3243.  *       file so that it will be automatically available in subsequent
  3244.  *       sessions.
  3245.  *
  3246.  *   Limits:
  3247.  *       Minor error checking is provided when OK is selected to make
  3248.  *       sure that the dates specified fall in the 20th and 21st
  3249.  *       centuries.  No error checking is attempted to verify correct
  3250.  *       month or day of month entries.
  3251.  *
  3252.  */
  3253.  
  3254.  #define INCL_WIN
  3255.  #include <os2.h>
  3256.  
  3257.  #include "bio.h"
  3258.  #include <math.h>
  3259.  #include <stdio.h>
  3260.  
  3261.  /* Read-only global variables */
  3262.  extern HAB      hAB;
  3263.  extern char     szAppName[];
  3264.  
  3265.  /* Global variables (modified) */
  3266.  extern long     SelectDay, Day;
  3267.  extern double   Born;
  3268.  extern BOOL     bBorn;
  3269.  
  3270.  /* Function prototypes */
  3271.  void InitBioDlg(HWND);
  3272.  void BioDlgCmd(HWND, MPARAM);
  3273.  
  3274.  MRESULT CALLBACK BioDlg( hDlg, message, mp1, mp2 )
  3275.  HWND    hDlg;
  3276.  USHORT  message;
  3277.  MPARAM  mp1;
  3278.  MPARAM  mp2;
  3279.  {
  3280.      switch( message ) {
  3281.          case WM_INITDLG:
  3282.              InitBioDlg(hDlg);
  3283.              break;
  3284.  
  3285.          case WM_COMMAND:
  3286.              BioDlgCmd(hDlg, mp1);
  3287.              break;
  3288.  
  3289.          default:
  3290.              return( WinDefDlgProc( hDlg, message, mp1, mp2 ) );
  3291.  
  3292.      }
  3293.      return 0L;
  3294.  }
  3295.  
  3296.  
  3297.  /*  About() - General purpose About dialog box.
  3298.  *
  3299.  *   Purpose:
  3300.  *       Provide program propoganda.
  3301.  *
  3302.  *   Arguments:
  3303.  *       hDlg          - Handle of Dialog Box owning message
  3304.  *       message       - Message itself
  3305.  *       mp1           - Extra message-dependent info
  3306.  *       mp2           - Extra message-dependent info
  3307.  */
  3308.  
  3309.  MRESULT CALLBACK About( hWndDlg, message, mp1, mp2 )
  3310.  HWND   hWndDlg;
  3311.  USHORT message;
  3312.  MPARAM  mp1;
  3313.  MPARAM  mp2;
  3314.  {
  3315.      switch( message )
  3316.      {
  3317.        case WM_COMMAND:
  3318.          switch( LOUSHORT( mp1 ) )
  3319.          {
  3320.            case DID_OK:
  3321.              WinDismissDlg( hWndDlg, TRUE );
  3322.              break;
  3323.  
  3324.            default:
  3325.              break;
  3326.          }
  3327.          break;
  3328.  
  3329.        default:
  3330.          return( WinDefDlgProc( hWndDlg, message, mp1, mp2 ) );
  3331.      }
  3332.      return( FALSE );
  3333.  }
  3334.  
  3335.  
  3336.  void InitBioDlg(HWND hDlg) {
  3337.  /*
  3338.       If valid OS2.INI info, fill in birthdate edit fields
  3339.  */
  3340.      USHORT        year, month;
  3341.      double      day;
  3342.  
  3343.      if (bBorn) {
  3344.        calendar( Born, (int *)&year, (int *)&month, &day );
  3345.        WinSetDlgItemShort( hDlg, ID_BDYEAR, year, FALSE );
  3346.        WinSetDlgItemShort( hDlg, ID_BDMONTH, month, FALSE );
  3347.        WinSetDlgItemShort( hDlg, ID_BDDAY, (int)day, FALSE );
  3348.      }
  3349.      /* Display current date or date highlighted */
  3350.      calendar( Born+SelectDay, (int *)&year, (int *)&month, &day );
  3351.      WinSetDlgItemShort( hDlg, ID_YEAR, year, FALSE );
  3352.      WinSetDlgItemShort( hDlg, ID_MONTH, month, FALSE );
  3353.      WinSetDlgItemShort( hDlg, ID_DAY, (int)day, FALSE );
  3354.  }
  3355.  
  3356.  
  3357.  void BioDlgCmd(HWND hDlg, MPARAM mp1) {
  3358.  /*
  3359.      Bio Dialog Box routine WM_COMMAND processor
  3360.  */
  3361.      USHORT        year, month, iDay;
  3362.      double      day;
  3363.      char        szBuf[10];
  3364.  
  3365.      switch( LOUSHORT( mp1 ) ) {
  3366.          case DID_OK:
  3367.              /* Get the birthday edit field values */
  3368.              WinQueryDlgItemShort( hDlg, ID_BDYEAR, &year, FALSE );
  3369.              WinQueryDlgItemShort( hDlg, ID_BDMONTH, &month, FALSE );
  3370.              WinQueryDlgItemShort( hDlg, ID_BDDAY, &iDay, FALSE );
  3371.              day = (double)iDay;
  3372.              /* Check that date is within acceptable range */
  3373.              if (year<1900 || year>2100) {
  3374.                 WinMessageBox( HWND_DESKTOP, hDlg,
  3375.                                "Dates valid from 1900-2100",
  3376.                                "Birthday!", 0,
  3377.                                MB_OK | MB_ICONEXCLAMATION );
  3378.                 break;
  3379.              }
  3380.              /* Get julian date of birth date */
  3381.              Born = julian( year, month, day );
  3382.  
  3383.              /* Write birth date to OS2.INI if check box checked */
  3384.              if (WinSendDlgItemMsg(hDlg, ID_OS2INI, BM_QUERYCHECK, 0L, 0L)) {
  3385.                     sprintf(szBuf, "%d", year);
  3386.                WinWriteProfileString( hAB, szAppName, "Year", szBuf );
  3387.                     sprintf(szBuf, "%d", month);
  3388.                WinWriteProfileString( hAB, szAppName, "Month", szBuf );
  3389.                     sprintf(szBuf, "%d", (int)day);
  3390.                WinWriteProfileString( hAB, szAppName, "Day", szBuf );
  3391.              }
  3392.  
  3393.              /* Get selected day of interest edit field values */
  3394.              WinQueryDlgItemShort( hDlg, ID_YEAR, &year, FALSE );
  3395.              WinQueryDlgItemShort( hDlg, ID_MONTH, &month, FALSE );
  3396.              WinQueryDlgItemShort( hDlg, ID_DAY, &iDay, FALSE );
  3397.              day = (double)iDay;
  3398.              /* Check that date is within acceptable range */
  3399.              if (year<1900 || year>2100) {
  3400.                 WinMessageBox( HWND_DESKTOP, hDlg,
  3401.                                "Dates valid from 1900-2100",
  3402.                                "Display Date!", 0,
  3403.                                MB_OK | MB_ICONEXCLAMATION );
  3404.                 break;
  3405.              }
  3406.  
  3407.              /* Compute number of days since birth */
  3408.                   SelectDay  = (long)(julian( year, month, day ) - Born);
  3409.              /* Top date of display is 3 days before selected day */
  3410.              Day = SelectDay - 3;
  3411.              /* Got a valid birthdate, enable all routines */
  3412.              bBorn = TRUE;
  3413.              WinDismissDlg( hDlg, TRUE );
  3414.              break;
  3415.  
  3416.          case DID_CANCEL:
  3417.              /* Exit and ignore entries */
  3418.              WinDismissDlg( hDlg, FALSE );
  3419.              break;
  3420.  
  3421.          default:
  3422.              break;
  3423.      }
  3424.  }
  3425.  
  3426.  
  3427.  BIOPAINT.C
  3428.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BIO\BIOPAINT.C
  3429.  
  3430.  /*
  3431.      biopaint.c        -   WM_PAINT processing and calendar conversion routine
  3432.  
  3433.      Created by Microsoft Corporation, 1989
  3434.  */
  3435.  #define INCL_WIN
  3436.  #define INCL_GPI
  3437.  #include <os2.h>
  3438.  
  3439.  #include "bio.h"
  3440.  #include <math.h>
  3441.  #include <stdio.h>
  3442.  
  3443.  /* Read-only global variables */
  3444.  extern double   Born;
  3445.  extern long     Day, SelectDay;
  3446.  extern BOOL     bBorn;
  3447.  extern FONTMETRICS tmFontInfo;
  3448.  extern int      LinesPerPage;
  3449.  extern RECTL    rclClient;
  3450.  extern SHORT        cxDateField;
  3451.  
  3452.  /* Read-only static variables */
  3453.  static double   Cycle[] = { 23.0, 28.0, 33.0 };
  3454.  static char     cDayOfWeek[] = "MTWTFSS";
  3455.  extern LONG     Color[];
  3456.  
  3457.  
  3458.  
  3459.  /*  APPPaint() - Parent window WM_PAINT processing routine.
  3460.  *
  3461.  *   Purpose:
  3462.  *       Routine to graph biorhythm cycles and tabulate dates.
  3463.  *
  3464.  *   Arguments:
  3465.  *       hWnd          - Handle of Window owning message
  3466.  *       message       - Message itself
  3467.  *       mp1           - Extra message-dependent info
  3468.  *       mp2           - Extra message-dependent info
  3469.  *
  3470.  *   Globals (static):
  3471.  *       Cycle[]       - Array holding period for phy/emot/int: 23,28,33
  3472.  *       cDayOfWeek[]  - Array of chars holding first letter of days of week.
  3473.  *       Color[]       - Set of colored pens used to identify cycles.
  3474.  *
  3475.  *   Globals (referenced):
  3476.  *       Born          - Birthdate in julian days.  Read from WIN.INI.
  3477.  *        SelectDay     - Current day being tracked, day is highlighted.
  3478.  *                        This is stored as the number of days from birthdate.
  3479.  *                        Initialized to present day in WM_CREATE processing.
  3480.  *       Day           - Day number from date born which is top line being
  3481.  *                       displayed.  Initially three days before SelectDay.
  3482.  *       bBorn         - Boolean indicating whether valid birtdate entered or
  3483.  *        rclClient     - Size of client area defined by WM_SIZE message
  3484.  *       LinesPerPage  - Number of system font lines on client area, defined
  3485.  *                       by WM_SIZE message handling
  3486.  *       tmFontInfo    - Text Metric structure defined during WM_CREATE
  3487.  *
  3488.  *   Description:
  3489.  *       Tabulates dates and graphs cycles.  On color displays, weekends
  3490.  *       are written in red.  The update rectangle is used to minimize
  3491.  *       repaint time of affected client area.
  3492.  */
  3493.  VOID APIENTRY APPPaint( hWnd )
  3494.  HWND   hWnd;
  3495.  {
  3496.      HPS         hPS;
  3497.      POINTL      ptl;
  3498.      int         y, i;
  3499.      int         start, last;
  3500.      char        szDay[16];
  3501.      int         Amplitude, offset;
  3502.      int         year, month;
  3503.      double      day;
  3504.      RECTL       rc, rcClip;
  3505.      int         DayOfWeek;
  3506.      HRGN        hrgnClip;
  3507.      POINTL        ptlTextBox[5];
  3508.  
  3509.      hPS = WinBeginPaint( hWnd, NULL, &rcClip );
  3510.  
  3511.      /* Erase client area */
  3512.      WinQueryWindowRect( hWnd, &rc );
  3513.      WinFillRect( hPS, &rc, CLR_WHITE );
  3514.  
  3515.      /* Label parts of table and graph. */
  3516.      ptl.y = rclClient.yTop - tmFontInfo.lMaxBaselineExt + /* Top line */
  3517.              tmFontInfo.lMaxDescender;
  3518.      ptl.x = 0;
  3519.      GpiCharStringAt( hPS, &ptl, 7L, (PCH)"   DATE" );
  3520.      ptl.x = cxDateField + tmFontInfo.lAveCharWidth;
  3521.      GpiCharStringAt( hPS, &ptl, 3L, (PCH)"LOW" );
  3522.      GpiQueryTextBox( hPS, 4L, "HIGH", TXTBOX_COUNT, ptlTextBox );
  3523.      ptl.x = rclClient.xRight - ptlTextBox[TXTBOX_CONCAT].x - tmFontInfo.lAveC
  3524.      GpiCharStringAt( hPS, &ptl, 4L, (PCH)"HIGH" );
  3525.  
  3526.      /* Underline labels from left to right across client area */
  3527.      ptl.y = rclClient.yTop - tmFontInfo.lMaxBaselineExt;
  3528.      ptl.x = 0;
  3529.      GpiMove( hPS, &ptl );
  3530.      ptl.x = rclClient.xRight;
  3531.      GpiLine( hPS, &ptl );
  3532.  
  3533.      /* Draw a vertical line separator between dates and cycles */
  3534.      ptl.y = rclClient.yTop;
  3535.      ptl.x = cxDateField;
  3536.      GpiMove( hPS, &ptl );
  3537.      ptl.y = rclClient.yBottom;
  3538.      GpiLine( hPS, &ptl );
  3539.  
  3540.      /* Draw a dotted vertical center line to reference cycles */
  3541.      GpiSetLineType( hPS, LINETYPE_DOT );
  3542.      ptl.x = (cxDateField + rclClient.xRight) / 2;
  3543.      GpiMove( hPS, &ptl );
  3544.      ptl.y = rclClient.yTop;
  3545.      GpiLine( hPS, &ptl );
  3546.      /* (Should not have to restore line type after EndPaint) */
  3547.      GpiSetLineType( hPS, LINETYPE_DEFAULT );
  3548.  
  3549.      /* Update only the range of lines which fall into update rectangle */
  3550.      start = (int)((rclClient.yTop - rcClip.yTop) / tmFontInfo.lMaxBaselineExt
  3551.      if (start<1)
  3552.         start = 1;
  3553.      last = (int)((rclClient.yTop - rcClip.yBottom) / tmFontInfo.lMaxBaselineE
  3554.      if (last>(LinesPerPage-1))
  3555.         last = LinesPerPage-1;
  3556.  
  3557.      /* Set clip rectangle to completely draw entire rectangle representing
  3558.         each date affected.  Start drawing one day before and after
  3559.         (outside clip rectangle) so that cycle lines will connect correctly
  3560.         with unaffected lines. */
  3561.      rcClip.yTop = rclClient.yTop - start*tmFontInfo.lMaxBaselineExt;
  3562.      start--;
  3563.      last++;
  3564.      rcClip.yBottom = rclClient.yTop - last*tmFontInfo.lMaxBaselineExt + 1;
  3565.      hrgnClip = GpiCreateRegion( hPS, 1L, &rcClip );
  3566.      GpiSetClipRegion( hPS, hrgnClip, &hrgnClip );
  3567.  
  3568.      /* List days and date */
  3569.      for (y=start; y<=last; y++) {
  3570.          /* Get the calendar date from julian day */
  3571.          calendar( Born+Day+y-1, &year, &month, &day );
  3572.          /* Get offset into days of the week initials array */
  3573.          DayOfWeek = (int)((LONG)(Born+Day+y) % 7);
  3574.          /* Assemble each of the parts in a buffer */
  3575.          sprintf(szDay, " %02d-%02d-%02d",
  3576.                  month, (int)day, year - (trunc4((double)year / 100)*100) );
  3577.          /* If color available, draw weekends in red */
  3578.          if (DayOfWeek > 4)
  3579.             GpiSetColor( hPS, CLR_RED );
  3580.          ptl.x = 0;
  3581.          ptl.y = rclClient.yTop - ((y+1)*tmFontInfo.lMaxBaselineExt -
  3582.                  tmFontInfo.lMaxDescender);
  3583.          GpiCharStringAt( hPS, &ptl, 1L, (PCH)&cDayOfWeek[DayOfWeek] );
  3584.          GpiQueryWidthTable( hPS, (LONG)'W', 1L, &ptl.x );
  3585.          GpiCharStringAt( hPS, &ptl, 9L, (PCH)szDay );
  3586.          GpiSetColor( hPS, CLR_BLACK );
  3587.      }
  3588.  
  3589.      /* Amplitude of sin wave is half client area minus space for dates */
  3590.      Amplitude = (int)((rclClient.xRight - cxDateField - tmFontInfo.lAveCharWi
  3591.      /* Move to right, make room for column of dates */
  3592.      offset = (int)(Amplitude + cxDateField + tmFontInfo.lAveCharWidth - (tmFo
  3593.      for (i=0; i<3 && bBorn; i++ ) {
  3594.          GpiSetColor( hPS, Color[i] );
  3595.          for (y=start; y<=last; y++) {
  3596.              ptl.x = (int)(sin( (y+Day-1)/Cycle[i]*2*3.14159 ) * Amplitude + o
  3597.              ptl.y = rclClient.yTop - (y*tmFontInfo.lMaxBaselineExt +
  3598.                          tmFontInfo.lMaxBaselineExt/2);
  3599.              if ((y+Day-1 > 0) && (y>start))
  3600.                 GpiLine( hPS, &ptl );
  3601.              else
  3602.                 GpiMove( hPS, &ptl );
  3603.          }
  3604.      }
  3605.  
  3606.      /* Draw highlight on selected day if visible. */
  3607.      if ((SelectDay >= Day) && (SelectDay - Day < LinesPerPage - 1)) {
  3608.          rc.xRight = rclClient.xRight;
  3609.          rc.xLeft = rclClient.xLeft;
  3610.          rc.yTop = rclClient.yTop - (int)(SelectDay - Day + 1) * tmFontInfo.lM
  3611.          rc.yBottom = rc.yTop - tmFontInfo.lMaxBaselineExt + 1;
  3612.          WinInvertRect( hPS, &rc );
  3613.      }
  3614.  
  3615.      WinEndPaint( hPS );
  3616.  
  3617.      return;
  3618.  }
  3619.  
  3620.  
  3621.  /*  julian() - Compute julian date from Gregorian calendar date.
  3622.  *
  3623.  *   Purpose:
  3624.  *       Provide a standard time base.
  3625.  *
  3626.  *   Arguments:
  3627.  *       year          - Calendar year
  3628.  *       month         - Calendar month
  3629.  *       day           - Calendar day and fraction
  3630.  *
  3631.  *   Return Value:
  3632.  *       double        - Julian date converted
  3633.  *
  3634.  *   Description:
  3635.  *       Convert Gregorian dates to Julian Days.  Refer to Alamanac for
  3636.  *       Computers (1978), p. B2, Naval Observatory Pub.
  3637.  *
  3638.  *   Limits:
  3639.  *       Valid between ~1900 and 2099.
  3640.  *
  3641.  */
  3642.  
  3643.  double PASCAL julian (year, month, day)
  3644.  int    year, month;
  3645.  double day;
  3646.  {
  3647.    double dj;
  3648.    double fracDay, intDay;
  3649.  
  3650.    fracDay = modf(day, &intDay);
  3651.    dj = (long)367*year - 7*(year + (month+9) / 12) / 4 + 275*month / 9 +
  3652.         intDay + 1721013.5 + fracDay;
  3653.    return dj;
  3654.  }
  3655.  
  3656.  
  3657.  /*  calendar() - Compute Gregorian calendar date from julian date.
  3658.  *
  3659.  *   Purpose:
  3660.  *       Provide a standard time base.
  3661.  *
  3662.  *   Arguments:
  3663.  *       juldate       - Julian date to convert
  3664.  *       year          - Calendar year result
  3665.  *       month         - Calendar month result
  3666.  *       day           - Calendar day and fraction result
  3667.  *
  3668.  *   Return Value:
  3669.  *       void
  3670.  *
  3671.  *   Globals (modified):
  3672.  *       none
  3673.  *
  3674.  *   Globals (referenced):
  3675.  *       none
  3676.  *
  3677.  *   Description:
  3678.  *       Convert Julian Days to Gregorian date.  Refer to Astronomical
  3679.  *       Formulae for Calculators (1979), p. 23, by Jean Meeus.
  3680.  *
  3681.  *   Limits:
  3682.  *       Valid for positive Julian Day values.
  3683.  *
  3684.  */
  3685.  
  3686.  void PASCAL calendar (juldate, year, month, day)
  3687.  double juldate;
  3688.  int *year;
  3689.  int *month;
  3690.  double *day;
  3691.  {
  3692.    long b, c, d, e, z, alf;
  3693.  
  3694.    juldate = juldate + 0.5;
  3695.    z = trunc4(juldate);
  3696.    alf = trunc4((z - 1867216.25)/36524.25);
  3697.    b = z + 1 + alf - alf / 4 + 1524;
  3698.    c = trunc4((b - 122.1)/365.25);
  3699.    d = 365*c + c / 4;
  3700.    e = trunc4((b - d)/30.6001);
  3701.    *day = b - d - trunc4(30.6001*e) + juldate - z;
  3702.    if (e > 13)
  3703.        *month = (int)e - 13;
  3704.    else
  3705.        *month = (int)e - 1;
  3706.    if (*month > 2)
  3707.        *year = (int)c - 4716;
  3708.    else
  3709.        *year = (int)c - 4715;
  3710.  }
  3711.  
  3712.  long PASCAL trunc4( dflValue )
  3713.  double dflValue;
  3714.  {
  3715.     double intValue;
  3716.     modf(dflValue, &intValue);
  3717.     return (long)intValue;
  3718.  }
  3719.  
  3720.  
  3721.  BMAP.C
  3722.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\MSNGR\BMAP.C
  3723.  
  3724.  /****************************** MODULE Header ******************************\
  3725.  * Module Name:  bmap.c - Messenger application - bitmap module
  3726.  *
  3727.  * Created: 8/1/89  sanfords
  3728.  *
  3729.  * Copyright (c) 1988, 1989  Microsoft Corporation
  3730.  \***************************************************************************/
  3731.  
  3732.  #include "msngr.h"
  3733.  #include "string.h"
  3734.  #ifdef SLOOP
  3735.  #define BITMAPINFOHEADER2 BITMAPINFOHEADER
  3736.  #define PBITMAPINFOHEADER2 PBITMAPINFOHEADER
  3737.  #define BITMAPINFO2 BITMAPINFO
  3738.  #define PBITMAPINFO2 PBITMAPINFO
  3739.  #endif
  3740.  
  3741.  typedef struct _CDATA {
  3742.      RECTL rcl;
  3743.      HBITMAP hbm;
  3744.      BOOL fSelect;
  3745.      BOOL fSelecting;
  3746.      NPUSERLIST npUL;
  3747.  } CDATA;
  3748.  typedef CDATA *NPCDATA;
  3749.  
  3750.  
  3751.  typedef struct _PKT {
  3752.      HBITMAP hbm;
  3753.      SHORT cx;
  3754.      SHORT cy;
  3755.      char szName[MAX_NAMESTR + 1];
  3756.  } PKT;
  3757.  typedef PKT *NPPKT;
  3758.  
  3759.  extern HWND hwndMsngr;
  3760.  extern SHORT cyText;
  3761.  extern HAB hab;
  3762.  extern HSZ hszAppName;
  3763.  extern HSZ hszEmailName;
  3764.  extern char szEmailName[];
  3765.  extern HWND hwndLB;
  3766.  extern ITEMLIST msgTopicItemList[];
  3767.  
  3768.  
  3769.  
  3770.  /*
  3771.   * local procs
  3772.   */
  3773.  MRESULT bmpInit(HWND hwnd, NPPKT ppktInit);
  3774.  MRESULT sndBmapInit(HWND hwnd, NPUSERLIST pUserItem);
  3775.  BOOL sndBmap(NPCDATA pcd);
  3776.  HBITMAP SnapRegion(HPS hps, PRECTL prcl);
  3777.  void DrawRgn(HPS hps, PRECTL prcl);
  3778.  void SortRect(PRECTL prcl, PRECTL prclSorted);
  3779.  HDC CreateDC(PSZ lpszDriver, HDC hdcCompat);
  3780.  
  3781.  #define max(a,b)    (((a) > (b)) ? (a) : (b))
  3782.  
  3783.  /*
  3784.   * file globals
  3785.   */
  3786.  ATOM fmtBmapPkt;
  3787.  HPOINTER hptrSelBmap = 0;
  3788.  HPOINTER hptrBmap = 0;
  3789.  
  3790.  void InitBmapModule()
  3791.  {
  3792.      fmtBmapPkt = WinAddAtom(WinQuerySystemAtomTable(), SZBMAPDATA);
  3793.      hptrSelBmap = WinLoadPointer(HWND_DESKTOP, (HMODULE)NULL, IDR_SELBMAP);
  3794.      hptrBmap = WinLoadPointer(HWND_DESKTOP, NULL, IDD_GETBITMAP);
  3795.  }
  3796.  
  3797.  void CloseBmapModule()
  3798.  {
  3799.      WinDeleteAtom(WinQuerySystemAtomTable(), fmtBmapPkt);
  3800.      WinDestroyPointer(hptrSelBmap);
  3801.      WinDestroyPointer(hptrBmap);
  3802.  }
  3803.  
  3804.  HDMGDATA bmpXfer(pXferInfo)
  3805.  PXFERINFO pXferInfo;
  3806.  {
  3807.      PBYTE pbuf;
  3808.      PKT pkt;
  3809.      PBITMAPINFO pbmi;
  3810.      HDC hdc;
  3811.      HPS hpsMem;
  3812.      SIZEL size;
  3813.  
  3814.      if (pXferInfo->usFmt != fmtBmapPkt)
  3815.          return(DDE_NOTPROCESSED);
  3816.  
  3817.      if (pXferInfo->usType == XTYP_POKE) {
  3818.          /*
  3819.           * we have bitmap bits...stick them into pkt.hbm.
  3820.           */
  3821.          pbuf = DdeAccessData(pXferInfo->hDmgData);
  3822.  
  3823.          DdeCopyBlock(pbuf, (PBYTE)&pkt.szName[0], MAX_NAMESTR + 1L);
  3824.          pbmi = (PBITMAPINFO)(pbuf + MAX_NAMESTR + 1);
  3825.  
  3826.          pkt.cx = pbmi->cx;
  3827.          pkt.cy = pbmi->cy;
  3828.          size.cx = (LONG)pkt.cx;
  3829.          size.cy = (LONG)pkt.cy;
  3830.          hdc = CreateDC((PSZ)"MEMORY", (HDC)NULL);
  3831.          hpsMem = GpiCreatePS(hab, hdc, &size,
  3832.                  PU_ARBITRARY | GPIT_NORMAL | GPIA_ASSOC );
  3833.          pkt.hbm = GpiCreateBitmap(hpsMem, (PBITMAPINFOHEADER2)pbmi, CBM_INIT,
  3834.                  (PBYTE)&pbmi->argbColor[1 << pbmi->cBitCount],
  3835.                  (PBITMAPINFO2)pbmi);
  3836.          GpiAssociate(hpsMem, NULL);
  3837.          GpiDestroyPS(hpsMem);
  3838.          DevCloseDC(hdc);
  3839.          DdeFreeData(pXferInfo->hDmgData);
  3840.  
  3841.          WinLoadDlg(HWND_DESKTOP, hwndMsngr, BmpDlgProc, 0L, IDD_GETBITMAP,
  3842.                  (PVOID)&pkt);
  3843.          return(1);
  3844.      }
  3845.      return(0);
  3846.  }
  3847.  
  3848.  
  3849.  /*
  3850.   * This is the proc used for receiving a bitmap
  3851.   */
  3852.  MRESULT EXPENTRY BmpDlgProc(hwnd, msg, mp1, mp2)
  3853.  HWND hwnd;
  3854.  USHORT msg;
  3855.  MPARAM mp1;
  3856.  MPARAM mp2;
  3857.  {
  3858.      HBITMAP hbm;
  3859.      HPS hps;
  3860.      WRECT wrc;
  3861.  
  3862.      switch(msg) {
  3863.      case WM_INITDLG:
  3864.          return(bmpInit(hwnd, (NPPKT)(SHORT)mp2));
  3865.          break;
  3866.  
  3867.      case WM_DESTROY:
  3868.          if (hbm = ((NPPKT)WinQueryWindowUShort(hwnd, QWS_USER))->hbm)
  3869.              GpiDeleteBitmap(hbm);
  3870.          WinFreeMem(hheap, (NPBYTE)WinQueryWindowUShort(hwnd, QWS_USER),
  3871.                  sizeof(PKT));
  3872.          break;
  3873.  
  3874.      case WM_WINDOWPOSCHANGED:
  3875.          /*
  3876.           * hide the OK button when minimized since it messes up the icon.
  3877.           */
  3878.          if ((LONG)mp2 & AWP_MINIMIZED)
  3879.              WinShowWindow(WinWindowFromID(hwnd, MBID_OK), FALSE);
  3880.          else if ((LONG)mp2 & AWP_RESTORED)
  3881.              WinShowWindow(WinWindowFromID(hwnd, MBID_OK), TRUE);
  3882.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  3883.          break;
  3884.  
  3885.      case WM_COMMAND:
  3886.          WinDestroyWindow(hwnd);
  3887.          break;
  3888.  
  3889.      case WM_PAINT:
  3890.          WinDefDlgProc(hwnd, msg, mp1, mp2);
  3891.          /*
  3892.           * draw the bitmap just above the OK button.
  3893.           */
  3894.          hps = WinGetPS(hwnd);
  3895.          WinQueryWindowRect(WinWindowFromID(hwnd, MBID_OK), (PRECTL)&wrc);
  3896.          WinMapWindowPoints(WinWindowFromID(hwnd, MBID_OK), hwnd, (PPOINTL)&wr
  3897.          wrc.yBottom = wrc.yTop + cyText / 2;
  3898.          hbm = ((NPPKT)WinQueryWindowUShort(hwnd, QWS_USER))->hbm;
  3899.          WinDrawBitmap(hps, hbm, (PRECTL)NULL, (PPOINTL)&wrc, 0L, 0L, DBM_NORM
  3900.          WinReleasePS(hps);
  3901.          break;
  3902.  
  3903.      default:
  3904.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  3905.      }
  3906.      return(0);
  3907.  }
  3908.  
  3909.  
  3910.  MRESULT bmpInit(hwnd, ppktInit)
  3911.  HWND hwnd;
  3912.  NPPKT ppktInit;
  3913.  {
  3914.      char szTitle[MAX_TITLESTR];
  3915.      WRECT wrc;
  3916.      NPPKT ppkt;
  3917.      SHORT cxMin;
  3918.  
  3919.      if (!(ppkt = (NPPKT)WinAllocMem(hheap, sizeof(PKT))))
  3920.          return(1);
  3921.      *ppkt = *ppktInit;
  3922.      WinSetWindowUShort(hwnd, QWL_USER, (USHORT)ppkt);
  3923.      /*
  3924.       * This is required because currently, automatic ICON resource loading
  3925.       * is not supported for dialogs.
  3926.       */
  3927.      WinSendMsg(hwnd, WM_SETICON, (MPARAM)hptrBmap, 0L);
  3928.      /*
  3929.       * Set up title.
  3930.       */
  3931.      WinQueryWindowText(hwnd, MAX_TITLESTR, (PSZ)szTitle);
  3932.      lstrcat(szTitle, szTitle, ppkt->szName);
  3933.      WinSetWindowText(hwnd, (PSZ)szTitle);
  3934.      /*
  3935.       * resize the dialog so the bitmap just fits.
  3936.       */
  3937.      WinQueryWindowRect(hwnd, (PRECTL)&wrc);
  3938.      cxMin = wrc.xRight;
  3939.      WinQueryWindowRect(WinWindowFromID(hwnd, MBID_OK), (PRECTL)&wrc);
  3940.      WinMapWindowPoints(WinWindowFromID(hwnd, MBID_OK), hwnd, (PPOINTL)&wrc, 2
  3941.      WinSetWindowPos(hwnd, NULL, 0, 0, max(wrc.xLeft * 2 + ppkt->cx, cxMin),
  3942.              wrc.yTop + ppkt->cy + cyText +
  3943.              (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR), SWP_SIZE);
  3944.      return(0);
  3945.  }
  3946.  
  3947.  
  3948.  
  3949.  MRESULT EXPENTRY SendBitmapDlgProc(hwnd, msg, mp1, mp2)
  3950.  HWND hwnd;
  3951.  USHORT msg;
  3952.  MPARAM mp1;
  3953.  MPARAM mp2;
  3954.  {
  3955.      NPCDATA pcd;
  3956.      POINTL pt;
  3957.      HPS hps;
  3958.  
  3959.      pcd = (NPCDATA)WinQueryWindowUShort(hwnd, QWS_USER);
  3960.  
  3961.      switch (msg) {
  3962.      case WM_INITDLG:
  3963.          return(sndBmapInit(hwnd, (NPUSERLIST)(SHORT)mp2));
  3964.          break;
  3965.  
  3966.      case WM_DESTROY:
  3967.          WinFreeMem(hheap, (NPBYTE)pcd, sizeof(CDATA));
  3968.          break;
  3969.  
  3970.      case WM_COMMAND:
  3971.          switch (LOUSHORT(mp1)) {
  3972.          case IDC_SENDBITMAP:
  3973.              if (sndBmap(pcd))
  3974.                  WinDismissDlg(hwnd, 0);
  3975.              break;
  3976.  
  3977.          case MBID_CANCEL:
  3978.              WinDismissDlg(hwnd, 0);
  3979.              break;
  3980.  
  3981.          case IDC_SELECT:
  3982.              pcd->fSelect = TRUE;
  3983.              WinSetCapture(HWND_DESKTOP, hwnd);
  3984.              break;
  3985.          }
  3986.          break;
  3987.  
  3988.      case WM_BUTTON1DOWN:
  3989.          if (pcd->fSelect) {
  3990.              if (pcd->hbm) {
  3991.                  GpiDeleteBitmap(pcd->hbm);
  3992.                  pcd->hbm = NULL;
  3993.              }
  3994.              WinSetRect(hab, &pcd->rcl, SHORT1FROMMP(mp1), SHORT2FROMMP(mp1),
  3995.                      SHORT1FROMMP(mp1), SHORT2FROMMP(mp1));
  3996.              WinMapWindowPoints(hwnd, (HWND)HWND_DESKTOP, (PPOINTL)&pcd->rcl,
  3997.              hps = WinGetScreenPS(HWND_DESKTOP);
  3998.              DrawRgn(hps, &pcd->rcl);
  3999.              WinReleasePS(hps);
  4000.              pcd->fSelecting = TRUE;
  4001.          }
  4002.          break;
  4003.  
  4004.      case WM_MOUSEMOVE:
  4005.          if (pcd->fSelect) {
  4006.              WinSetPointer(HWND_DESKTOP, hptrSelBmap);
  4007.          } else {
  4008.              WinSetPointer(HWND_DESKTOP,
  4009.                      WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
  4010.          }
  4011.          if (pcd->fSelecting) {
  4012.              hps = WinGetScreenPS(HWND_DESKTOP);
  4013.              DrawRgn(hps, &pcd->rcl);    /* erase old rect */
  4014.              pt.x = SHORT1FROMMP(mp1);
  4015.              pt.y = SHORT2FROMMP(mp1);
  4016.              WinMapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
  4017.              pcd->rcl.xRight = pt.x;
  4018.              pcd->rcl.yTop = pt.y;
  4019.              DrawRgn(hps, &pcd->rcl);    /* draw new one */
  4020.              WinReleasePS(hps);
  4021.          }
  4022.          break;
  4023.  
  4024.      case WM_BUTTON1UP:
  4025.          if (pcd->fSelecting) {
  4026.              WinSetCapture(HWND_DESKTOP, (HWND)NULL);
  4027.              hps = WinGetScreenPS(HWND_DESKTOP);
  4028.              DrawRgn(hps, &pcd->rcl);
  4029.              pcd->hbm = SnapRegion(hps, &pcd->rcl);
  4030.              WinReleasePS(hps);
  4031.              pcd->fSelecting = FALSE;
  4032.              pcd->fSelect = FALSE;
  4033.              WinEnableWindow(WinWindowFromID(hwnd, IDC_SENDBITMAP),
  4034.                      !WinIsRectEmpty(hab, &pcd->rcl));
  4035.          }
  4036.          break;
  4037.  
  4038.  
  4039.      default:
  4040.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  4041.          break;
  4042.      }
  4043.      return(0);
  4044.  }
  4045.  
  4046.  
  4047.  /*
  4048.   * returns fFailed
  4049.   */
  4050.  MPARAM sndBmapInit(hwnd, pUserItem)
  4051.  HWND hwnd;
  4052.  NPUSERLIST pUserItem;
  4053.  {
  4054.      NPCDATA pcd;
  4055.      char szTitle[MAX_TITLESTR];
  4056.      char szName[MAX_NAMESTR];
  4057.  
  4058.      if (!(pcd = (NPCDATA)WinAllocMem(hheap, sizeof(CDATA))))
  4059.          return(1);
  4060.      WinSetRectEmpty(hab, &pcd->rcl);
  4061.      pcd->hbm = NULL;
  4062.      pcd->fSelect = FALSE;
  4063.      pcd->fSelecting = FALSE;
  4064.      pcd->npUL = pUserItem;
  4065.      if (pcd->npUL->hConvMsg == NULL) {
  4066.          NotifyUser(SZCANTCONNECT);
  4067.          return(1);
  4068.      }
  4069.      WinQueryWindowText(hwnd, MAX_TITLESTR, szTitle);
  4070.      DdeGetHszString(pcd->npUL->hsz, szName, (LONG)MAX_NAMESTR);
  4071.      lstrcat(szTitle, szTitle, szName);
  4072.      WinSetWindowText(hwnd, (PSZ)szTitle);
  4073.      WinSetWindowUShort(hwnd, QWS_USER, (USHORT)pcd);
  4074.      return(0);
  4075.  }
  4076.  
  4077.  
  4078.  BOOL sndBmap(pcd)
  4079.  NPCDATA pcd;
  4080.  {
  4081.      BITMAPINFOHEADER bih;
  4082.      SHORT cbBuffer, cbBitmapInfo;
  4083.      PBYTE pbBuffer;
  4084.      PBITMAPINFO pbmi;
  4085.      PSZ pszName;
  4086.      SEL sel;
  4087.      HPS hps;
  4088.      HDC hdc;
  4089.      SIZEL size;
  4090.  
  4091.      /*
  4092.       * Compute the size of the image-data buffer and the bitmap information
  4093.       * structure.
  4094.       */
  4095.      GpiQueryBitmapParameters(pcd->hbm, &bih);
  4096.      cbBuffer = (((bih.cBitCount * bih.cx) + 31) / 32) * 4;
  4097.      if (cbBuffer > 0xFFFF / bih.cy / bih.cPlanes) {
  4098.          NotifyUser(SZTOOBIG);
  4099.          return(FALSE);
  4100.      }
  4101.      cbBuffer *= bih.cy * bih.cPlanes;
  4102.      cbBitmapInfo = sizeof(BITMAPINFO) +
  4103.          (sizeof(RGB) * (1 << bih.cBitCount));
  4104.  
  4105.      /*
  4106.       * Allocate memory for the image data-buffer and the bitmap information
  4107.       * structure.
  4108.       */
  4109.      DosAllocSeg(cbBuffer + cbBitmapInfo + MAX_NAMESTR + 1, &sel, 0);
  4110.      pszName = (PSZ)MAKEP(sel, 0);
  4111.      lstrcpy(pszName, szEmailName);
  4112.      pbmi = (PBITMAPINFO)(pszName + MAX_NAMESTR + 1);
  4113.      pbBuffer = (PBYTE)&pbmi->argbColor[1 << bih.cBitCount];
  4114.      *(PBITMAPINFOHEADER)pbmi = bih;
  4115.  
  4116.      size.cx = (LONG)bih.cx;
  4117.      size.cy = (LONG)bih.cy;
  4118.      hdc = CreateDC((PSZ)"MEMORY", (HDC)NULL);
  4119.      hps = GpiCreatePS(hab, hdc, &size,
  4120.              PU_ARBITRARY | GPIT_NORMAL | GPIA_ASSOC );
  4121.      GpiSetBitmap(hps, pcd->hbm);
  4122.      GpiQueryBitmapBits(hps, 0L, (LONG)bih.cy, (PBYTE)pbBuffer,
  4123.              (PBITMAPINFO2)pbmi);
  4124.      GpiAssociate(hps, NULL);
  4125.      GpiDestroyPS(hps);
  4126.      DevCloseDC(hdc);
  4127.  
  4128.      if (!DdeClientXfer(pszName,
  4129.              (LONG)(cbBuffer + cbBitmapInfo + MAX_NAMESTR + 1),
  4130.              pcd->npUL->hConvMsg,
  4131.              msgTopicItemList[IIL_BMPXFER].hszItem,
  4132.              fmtBmapPkt, XTYP_POKE, ulTimeout, 0L)) {
  4133.          MyPostError(DdeGetLastError());
  4134.      }
  4135.  
  4136.      DosFreeSeg(sel);
  4137.      GpiDeleteBitmap(pcd->hbm);
  4138.      pcd->hbm = NULL;
  4139.      WinSetRectEmpty(hab, &pcd->rcl);
  4140.      return(TRUE);
  4141.  }
  4142.  
  4143.  
  4144.  HBITMAP SnapRegion(hps, prcl)
  4145.  HPS hps;
  4146.  PRECTL prcl;
  4147.  {
  4148.      HDC hdc;
  4149.      HBITMAP hbm, hbmOld;
  4150.      BITMAPINFOHEADER bih;
  4151.      POINTL rgpt[3];
  4152.      HPS hpsMem;
  4153.      SIZEL size;
  4154.  
  4155.      SortRect(prcl, prcl);
  4156.      WinInflateRect(hab, prcl, -1, -1);
  4157.  
  4158.      size.cx = (USHORT)(prcl->xRight - prcl->xLeft);
  4159.      size.cy = (USHORT)(prcl->yTop - prcl->yBottom);
  4160.  
  4161.      /* Create a memory DC */
  4162.      hdc = CreateDC((PSZ)"MEMORY", (HDC)NULL);
  4163.  
  4164.      /* create a memory PS */
  4165.      hpsMem = GpiCreatePS(hab, hdc, &size,
  4166.              PU_ARBITRARY | GPIT_NORMAL | GPIA_ASSOC );
  4167.  
  4168.      /* Create a bitmap */
  4169.      bih.cbFix = sizeof(BITMAPINFOHEADER);
  4170.      bih.cx = (SHORT)size.cx;
  4171.      bih.cy = (SHORT)size.cy;
  4172.      bih.cPlanes = 1;
  4173.      bih.cBitCount = 8;
  4174.      hbm = GpiCreateBitmap(hpsMem, (PBITMAPINFOHEADER2)&bih, 0L, 0, 0);
  4175.      if (hbm == GPI_ERROR)
  4176.          return(0);
  4177.  
  4178.      /* put the bitmap into the memory PS */
  4179.      hbmOld = GpiSetBitmap(hpsMem, hbm);
  4180.  
  4181.      /* copy the window to the memory PS */
  4182.      rgpt[0].x = 0;
  4183.      rgpt[0].y = 0;
  4184.      rgpt[1].x = size.cx;
  4185.      rgpt[1].y = size.cy;
  4186.      rgpt[2].x = prcl->xLeft;
  4187.      rgpt[2].y = prcl->yBottom;
  4188.      GpiBitBlt(hpsMem, hps, 3L, (PPOINTL)&rgpt[0], ROP_SRCCOPY, 0L);
  4189.  
  4190.      /* free the bitmap */
  4191.      GpiSetBitmap(hpsMem, hbmOld);
  4192.  
  4193.      /* destroy the memory DC */
  4194.      GpiAssociate(hpsMem, NULL);
  4195.      GpiDestroyPS(hpsMem);
  4196.      DevCloseDC(hdc);
  4197.      return(hbm);
  4198.  } /* end snapregion */
  4199.  
  4200.  
  4201.  HDC CreateDC(lpszDriver, hdcCompat)
  4202.  PSZ  lpszDriver;
  4203.  HDC hdcCompat;
  4204.  {
  4205.      struct {
  4206.          ULONG FAR *lpLogAddr;
  4207.          PSZ  lpszDriver;
  4208.      } opendc;
  4209.  
  4210.      opendc.lpLogAddr = NULL;
  4211.      opendc.lpszDriver = lpszDriver;
  4212.  
  4213.      return((HDC)DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 2L,
  4214.              (PDEVOPENDATA)&opendc, hdcCompat));
  4215.  }
  4216.  
  4217.  
  4218.  void DrawRgn(hps, prcl)
  4219.  HPS hps;
  4220.  PRECTL prcl;
  4221.  {
  4222.      RECTL rclSorted;
  4223.  
  4224.      SortRect(prcl, &rclSorted);
  4225.      WinDrawBorder(hps, &rclSorted, 1, 1, SYSCLR_WINDOW, SYSCLR_WINDOW,
  4226.              DB_DESTINVERT | DB_STANDARD);
  4227.  }
  4228.  
  4229.  void SortRect(prcl, prclSorted)
  4230.  PRECTL prcl;
  4231.  PRECTL prclSorted;
  4232.  {
  4233.      LONG l;
  4234.  
  4235.      WinCopyRect(hab, prclSorted, prcl);
  4236.      if (prclSorted->yTop < prclSorted->yBottom) {
  4237.          l = prclSorted->yBottom;
  4238.          prclSorted->yBottom = prclSorted->yTop;
  4239.          prclSorted->yTop = l;
  4240.      }
  4241.  
  4242.      if (prclSorted->xRight < prclSorted-> xLeft) {
  4243.          l = prclSorted->xRight;
  4244.          prclSorted->xRight = prclSorted->xLeft;
  4245.          prclSorted->xLeft = l;
  4246.      }
  4247.  }
  4248.  
  4249.  
  4250.  
  4251.  
  4252.  
  4253.  
  4254.  BROWSE.C
  4255.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BROWSE\AVBROWSE\BROWSE.C
  4256.  
  4257.  /*
  4258.      browse.c -- AVIO File Browsing Utility
  4259.  
  4260.      Created by Microsoft Corporation, 1989
  4261.  */
  4262.  #define        INCL_WINTRACKRECT
  4263.  #define        INCL_WINWINDOWMGR
  4264.  #define        INCL_WINPOINTERS
  4265.  #define INCL_WINFRAMEMGR
  4266.  #include <os2.h>
  4267.  #include <stdio.h>
  4268.  #include <stdlib.h>
  4269.  #include <string.h>
  4270.  #include "avio.h"
  4271.  #include "browse.h"
  4272.  #include <opendlg.h>
  4273.  /*
  4274.      Constants
  4275.  */
  4276.  #define MAXLINELEN        120
  4277.  #define AVIO_PS_ROWS        25
  4278.  #define        AVIO_PS_COLS        80
  4279.  /*
  4280.      Global Variables
  4281.  */
  4282.  FILE        *pfInput;
  4283.  PFNWP        pfnOldClient;
  4284.  char        *aszLines[NUM_DATA_LINES];
  4285.  SHORT        sTopLine = 0;
  4286.  DLF        dlfInput;
  4287.  HFILE        hfInput;
  4288.  USHORT        usAction;
  4289.  LBINFO        lbiData;
  4290.  HPOINTER hptrWait;
  4291.  HPOINTER hptrArrow;
  4292.  HWND        hWndClient;
  4293.  HWND        hWndFrame;
  4294.  BOOL        fLargeFont = FALSE;
  4295.  SHORT        sMaxLine;
  4296.  /*
  4297.      Open the input file
  4298.  */
  4299.  int cdecl main(int argc, char *argv[]) {
  4300.       static CHAR szClientClass[] = "Browse";
  4301.       static CHAR szCaption[]         = "";
  4302.       HAB        hAB;
  4303.       HMQ        hmq;
  4304.       QMSG        qmsg;
  4305.       ULONG        flFrameFlags = FCF_STANDARD | FCF_HORZSCROLL | FCF_VERTSCRO
  4306.       ULONG         flFrameStyle = WS_VISIBLE | FS_SCREENALIGN;
  4307.       char        *szInFile;
  4308.  
  4309.       hAB = WinInitialize(0);
  4310.       hmq = WinCreateMsgQueue(hAB, 0);
  4311.  
  4312.       WinRegisterClass(hAB, szClientClass, BrowseWndProc, CS_SYNCPAINT, 0);
  4313.  
  4314.       hWndFrame = WinCreateStdWindow(HWND_DESKTOP, flFrameStyle,
  4315.                                      &flFrameFlags, szClientClass, szCaption,
  4316.                                       0L, (HMODULE) NULL, ID_RESOURCE, &hWndCl
  4317.       /*
  4318.          Get the hourglass and arrow pointers
  4319.       */
  4320.       hptrWait  = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT,  FALSE);
  4321.       hptrArrow = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE);
  4322.  
  4323.       if (argc == 1) pfInput = stdin;
  4324.       else {
  4325.          if (!(pfInput = fopen(argv[1], "r"))) {
  4326.              fprintf(stderr, "***Error:  Could not open %s", szInFile);
  4327.              return(-1);
  4328.          }
  4329.       }
  4330.       ReadFile();
  4331.       /*
  4332.          Setup AVIO PS and force a paint
  4333.          Note:  This subclasses the client and frame windows
  4334.       */
  4335.       lbiData.sPSrows        = AVIO_PS_ROWS;
  4336.       lbiData.sPScols        = AVIO_PS_COLS;
  4337.       lbiData.sRows        = sTopLine;
  4338.       lbiData.sCols        = sMaxLine;
  4339.       lbiData.pfnQL        = (PFNQL) RetrieveLine;
  4340.       lbiData.fLargeFont        = FALSE;
  4341.       AvioInit(&lbiData);
  4342.       /*
  4343.          Process messages
  4344.       */
  4345.       while (WinGetMsg(hAB, &qmsg, NULL, 0, 0)) WinDispatchMsg(hAB, &qmsg);
  4346.  
  4347.       /* Blast the AVIO PS */
  4348.       AvioClose();
  4349.  
  4350.       WinDestroyWindow(hWndFrame);
  4351.       WinDestroyMsgQueue(hmq);
  4352.       WinTerminate(hAB);
  4353.       return 0;
  4354.  }
  4355.  
  4356.  void ReadFile(void) {
  4357.  /*
  4358.      Reads in a file using <stdio.h> fgets() calls.
  4359.      It might be wise to put better word wrap facilities here
  4360.  */
  4361.      char        szLine[MAXLINELEN];
  4362.  
  4363.      /* Put up the hourglass */
  4364.      WinSetPointer(HWND_DESKTOP, hptrWait);
  4365.  
  4366.      /* Reinitialize buffer, MaxLineLength */
  4367.      for (; sTopLine > 0; ) free(aszLines[--sTopLine]);
  4368.      sMaxLine = 0;
  4369.  
  4370.      /* Read in the file */
  4371.      while (fgets(szLine, MAXLINELEN, pfInput)) {
  4372.  
  4373.          /* Convert LF (\n) into NULL (\0) */
  4374.          if (szLine[strlen(szLine) - 1] == '\n') {
  4375.              szLine[strlen(szLine) - 1] = 0;
  4376.          } else szLine[MAXLINELEN - 1] = 0;
  4377.  
  4378.          if (StoreLine(szLine)) {
  4379.              fprintf(stderr,"***Error:  Line buffer full\n");
  4380.              return;
  4381.          }
  4382.      }
  4383.      fclose(pfInput);
  4384.  
  4385.      /* Reset the mouse pointer */
  4386.      WinSetPointer(HWND_DESKTOP, hptrArrow);
  4387.  
  4388.      return;
  4389.  }
  4390.  
  4391.  SHORT StoreLine(char *szLine) {
  4392.  /*
  4393.      Put a line into the line buffer; line numbers are free
  4394.      For > 64K data, add code here and in RetrieveLine
  4395.  */
  4396.      int                i, cLinePos;
  4397.      BOOL        fDone;
  4398.      /*
  4399.          Check if top line exceeded, or malloc() fails
  4400.      */
  4401.      if (sTopLine == NUM_DATA_LINES)  return -1;
  4402.      /*
  4403.          Compute line length with tabs expanded
  4404.      */
  4405.      cLinePos = 0;
  4406.      for (i = 0; i < MAXLINELEN; i++) {
  4407.          switch(szLine[i]) {
  4408.              case '\0':
  4409.                  cLinePos++; i = MAXLINELEN;
  4410.                  break;
  4411.              case '\t':
  4412.                  do {
  4413.                      cLinePos++;
  4414.                  } while (cLinePos % 8);
  4415.                  break;
  4416.  
  4417.              default:
  4418.                  cLinePos++;
  4419.          }
  4420.  
  4421.      }
  4422.      if (cLinePos > sMaxLine) sMaxLine = cLinePos;
  4423.      if (!(aszLines[sTopLine] = malloc(cLinePos))) return -1;
  4424.      /*
  4425.          Copy szLine into the line buffer.  Expand tabs here.
  4426.      */
  4427.      i = cLinePos = 0; fDone = FALSE;
  4428.      while ((i <= MAXLINELEN) && (!fDone)) {
  4429.          switch(szLine[i]) {
  4430.              case '\t':
  4431.                  do {
  4432.                      aszLines[sTopLine][cLinePos++] = ' ';
  4433.                  } while (cLinePos % 8);
  4434.                  break;
  4435.  
  4436.              default:
  4437.                  aszLines[sTopLine][cLinePos++] = szLine[i];
  4438.                  fDone = !szLine[i];
  4439.                  break;
  4440.          }
  4441.          i++;
  4442.      }
  4443.      sTopLine++;
  4444.      return 0;
  4445.  }
  4446.  
  4447.  char * _loadds RetrieveLine(USHORT usLineNum) {
  4448.  /*
  4449.      Return line numbered usLineNum
  4450.  */
  4451.      if ((SHORT) usLineNum >= sTopLine) {                /* Out of range */
  4452.          return NULL;
  4453.      }
  4454.      return aszLines[usLineNum];
  4455.  }
  4456.  
  4457.  MRESULT CALLBACK BrowseWndProc(hWnd, msg, mp1, mp2)
  4458.  HWND hWnd;
  4459.  USHORT msg;
  4460.  MPARAM mp1;
  4461.  MPARAM mp2;
  4462.  {
  4463.  /*
  4464.      Handle the About... and Open... messages
  4465.  */
  4466.      switch(msg) {
  4467.          case WM_COMMAND:
  4468.              switch (COMMANDMSG(&msg)->cmd) {
  4469.                  case IDM_ABOUT:
  4470.                      WinDlgBox(HWND_DESKTOP, hWnd, AboutDlgProc,
  4471.                                (HMODULE) NULL, IDD_ABOUT, NULL);
  4472.                      return 0;
  4473.  
  4474.                  case IDM_OPEN:
  4475.                      /*
  4476.                          Open the file, using the file dialog
  4477.                          then reopen it with stdio calls
  4478.                      */
  4479.                      SetupDLF(&dlfInput, DLG_OPENDLG, &hfInput,
  4480.                          "\\*.*", NULL, "Browse Open File",
  4481.                          "Select a file to be browsed.");
  4482.                      DlgFile(hWnd, &dlfInput);
  4483.                      pfInput = fopen(dlfInput.szOpenFile, "r");
  4484.                      ReadFile();
  4485.                      /*
  4486.                          Close the opened handle
  4487.                      */
  4488.                      DosClose(hfInput);
  4489.  
  4490.                      /* Fix up the screen display */
  4491.                      lbiData.sRows = sTopLine;
  4492.                      lbiData.sCols = sMaxLine;
  4493.                      lbiData.fLargeFont = fLargeFont;
  4494.                      AvioInit(&lbiData);
  4495.  
  4496.                      return 0;
  4497.  
  4498.                  case IDM_FONT:
  4499.                      AvioLargeFont(fLargeFont = !fLargeFont);
  4500.                         return 0;
  4501.  
  4502.                  default: return 0;
  4503.              }
  4504.              break;
  4505.          default: return WinDefWindowProc(hWnd, msg, mp1, mp2);
  4506.      }
  4507.      return 0L;
  4508.  }
  4509.  
  4510.  MRESULT CALLBACK AboutDlgProc(hDlg, msg, mp1, mp2)
  4511.  /*
  4512.      About... dialog procedure
  4513.  */
  4514.  HWND        hDlg;
  4515.  USHORT        msg;
  4516.  MPARAM        mp1;
  4517.  MPARAM        mp2;
  4518.  {
  4519.      switch(msg) {
  4520.          case WM_COMMAND:
  4521.              switch(COMMANDMSG(&msg)->cmd) {
  4522.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  4523.                  default: break;
  4524.              }
  4525.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  4526.      }
  4527.      return FALSE;
  4528.  }
  4529.  
  4530.  
  4531.  BROWSE.C
  4532.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\BROWSE\VBROWSE\BROWSE.C
  4533.  
  4534.  /*
  4535.      VIO File Browsing Application
  4536.      Created by Microsoft Corporation, 1989
  4537.  */
  4538.  #define         INCL_KBD
  4539.  #define         INCL_VIO
  4540.  #include <stdio.h>
  4541.  #include <stdlib.h>
  4542.  #include <os2.h>
  4543.  #include <string.h>
  4544.  #include "browse.h"
  4545.  /*
  4546.      Global Variables
  4547.  */
  4548.  FILE        *pfInput;
  4549.  char        *aszLines[NUM_DATA_LINES];
  4550.  SHORT        sTopLine= -1;
  4551.  SHORT        sRows;
  4552.  SHORT        HorScrollPos=0;
  4553.  BYTE        abBlank[2] = { 0x20, 0x07 };
  4554.  
  4555.  /*
  4556.      Macros for Vio calls
  4557.      The last parameter is zero because we're using a VIO PS
  4558.  */
  4559.  #define ClearScreen()        VioScrollDn(0, 0, -1, -1, -1, abBlank, 0)
  4560.  #define        Move(r,c)        VioSetCurPos(r, c, 0)
  4561.  #define ScrollDown(n)        VioScrollDn(0, 0, -1, -1,  n, abBlank, 0)
  4562.  #define ScrollUp(n)        VioScrollUp(0, 0, -1, -1,  n, abBlank, 0)
  4563.  #define Write(s)        VioWrtTTY(s, strlen(s), 0)
  4564.  /*
  4565.      Macros for bounds checking
  4566.  */
  4567.  #define Abs(x)                (((x) > 0) ? (x) : (-(x)))
  4568.  #define Max(x, y)        (((x) > (y)) ? (x) : (y))
  4569.  #define Min(x, y)        (((x) < (y)) ? (x) : (y))
  4570.  #define LowerBound(pos, disp, lbound)        Max(pos - disp, lbound)
  4571.  #define UpperBound(pos, disp, ubound)        Min(pos + disp, ubound)
  4572.  
  4573.  /*
  4574.      Functions
  4575.  */
  4576.  int cdecl main(int argc, char *argv[]) {
  4577.  /*
  4578.      Open the input file and initialize globals
  4579.  */
  4580.      char        *szFilename;
  4581.      VIOMODEINFO        viomiMode;
  4582.  
  4583.      /*
  4584.          Open the Input File
  4585.      */
  4586.      if (argc == 1)
  4587.          pfInput = stdin;
  4588.      else {
  4589.          szFilename = argv[1];
  4590.          if (!(pfInput = fopen(szFilename,"r"))) {
  4591.              fprintf(stderr, "***Error:  Could not open %s", szFilename);
  4592.              return(-1);
  4593.          }
  4594.      }
  4595.      /*
  4596.          Read it into the line buffer
  4597.      */
  4598.      if (ReadFile()) return(-1);
  4599.      /*
  4600.          Get the video parameters
  4601.      */
  4602.      viomiMode.cb = sizeof(viomiMode);
  4603.      VioGetMode(&viomiMode, 0);
  4604.      sRows = (SHORT) viomiMode.row;
  4605.  
  4606.      DisplayScreen(0, TRUE);
  4607.      ManipulateFile();
  4608.  
  4609.      return 0;
  4610.  }
  4611.  
  4612.  SHORT ReadFile(VOID) {
  4613.  /*
  4614.      Read lines from the file into the line buffer
  4615.      If there's an error, abort the program (return -1)
  4616.  */
  4617.      char szLine[MAXLINELENGTH];
  4618.  
  4619.      while (fgets(szLine, MAXLINELENGTH, pfInput)) {
  4620.  
  4621.          /* Convert LF (\n) character to NULL (\0) */
  4622.          if (szLine[strlen(szLine)-1] == '\n')
  4623.              szLine[strlen(szLine)-1] = 0;
  4624.          else {
  4625.              fprintf(stderr,"***Error:  Incomplete line read\n");
  4626.              return(-1);
  4627.          }
  4628.  
  4629.          /* Put the line into the line buffer */
  4630.          if (StoreLine(szLine)) {
  4631.              fprintf(stderr,"***Error:  Line buffer full\n");
  4632.              return(-1);
  4633.          }
  4634.      }
  4635.  
  4636.      /* Close the Input file */
  4637.      fclose(pfInput);
  4638.      return 0;
  4639.  }
  4640.  
  4641.  VOID ManipulateFile(VOID) {
  4642.  /*
  4643.      Main loop for display processing
  4644.  */
  4645.      CHAR    ch;
  4646.      SHORT   sLine = 0;
  4647.  
  4648.      /* The main command loop */
  4649.      while ((ch = GetKbdInput()) != ESC) {
  4650.          /*
  4651.              Take user input and compute new top line of screen
  4652.              by taking appropriate jump in jumptable.
  4653.  
  4654.              Note:  no horizontal scrolling.
  4655.          */
  4656.          switch (ch) {
  4657.          case LINE_UP:         sLine = LowerBound(sLine, 1, 0);
  4658.          case LINE_DOWN:  sLine = UpperBound(sLine, 1, BOTTOM);
  4659.          case PAGE_UP:         sLine = LowerBound(sLine, sRows, 0);
  4660.          case PAGE_DOWN:  sLine = UpperBound(sLine, sRows, BOTTOM);        bre
  4661.          case HOME_KEY:         sLine = 0;
  4662.          case END_KEY:         sLine = BOTTOM;
  4663.          default:                                                        break
  4664.          }
  4665.          DisplayScreen((USHORT) sLine, !ch);
  4666.      }
  4667.  
  4668.      /* Set Cursor to the bottom of the screen */
  4669.      Move((USHORT) sRows - 1, 0);
  4670.  }
  4671.  
  4672.  SHORT StoreLine(char *szLine) {
  4673.  /*
  4674.      Put a line into the line buffer; line numbers are free
  4675.      For > 64K data, add code here and in RetrieveLine
  4676.  */
  4677.      /*
  4678.          Check if top line exceeded, or if malloc() fails
  4679.      */
  4680.      if ((sTopLine == NUM_DATA_LINES) ||
  4681.          ((aszLines[++sTopLine] = malloc(strlen(szLine) + 1)) == NULL))
  4682.  
  4683.          return -1;
  4684.      /*
  4685.          Copy szLine into the line buffer
  4686.      */
  4687.      strcpy(aszLines[sTopLine], szLine);
  4688.      return 0;
  4689.  }
  4690.  
  4691.  SHORT RetrieveLine(char **pszLine , USHORT usLineNum) {
  4692.  /*
  4693.      Return line numbered usLineNum
  4694.  */
  4695.      if ((SHORT) usLineNum > sTopLine) return -1;  /* Out of range */
  4696.      *pszLine = aszLines[usLineNum];
  4697.      return 0;
  4698.  }
  4699.  
  4700.  VOID DisplayScreen(USHORT usDisplayTop, BOOL fForceDraw) {
  4701.  /*
  4702.      Display lines on the screen, starting at usDisplayTop
  4703.      by scrolling, then painting new information
  4704.  */
  4705.      SHORT            sDelta;
  4706.      static USHORT   usOldDispTop;
  4707.  
  4708.      sDelta = usDisplayTop - usOldDispTop;
  4709.      /*
  4710.          If only a few lines need repainting...
  4711.      */
  4712.      if ((Abs(sDelta) < sRows) && !fForceDraw ) {
  4713.          /*
  4714.              Moving to a "higher line", so:
  4715.                  Scroll down by the amount (make the difference positive)
  4716.                  Paint in the lines at the top
  4717.          */
  4718.          if (sDelta < 0) {
  4719.              ScrollDown(-sDelta);
  4720.              Refresh(usDisplayTop, -sDelta, 0);
  4721.          } else {
  4722.              /*
  4723.                  Moving to a "lower line", so:
  4724.                  Scroll the information up, and paint at the bottom
  4725.              */
  4726.              ScrollUp(sDelta);
  4727.              Refresh(usDisplayTop + sRows - sDelta, sDelta, sRows - sDelta);
  4728.          }
  4729.      } else {        /* Paint the entire screen */
  4730.          ClearScreen();
  4731.          Refresh(usDisplayTop, sRows, 0);
  4732.      }
  4733.      usOldDispTop = usDisplayTop;
  4734.  }
  4735.  
  4736.  VOID Refresh (USHORT iLine, USHORT usLines, USHORT usStart) {
  4737.  /*
  4738.      Updates usLines lines, starting at line iLine in the line
  4739.      buffer, and line usStart on the screen
  4740.  */
  4741.      USHORT usLine;
  4742.      char   *szLine;
  4743.  
  4744.      for (usLine = 0; usLine < usLines; usLine++) {
  4745.          /*
  4746.              Read the line, set the cursor, print the line
  4747.          */
  4748.          if (RetrieveLine(&szLine, (iLine + usLine))) break;
  4749.          Move((usStart + usLine), 0);
  4750.          Write(szLine);
  4751.      }
  4752.  }
  4753.  
  4754.  CHAR GetKbdInput(VOID) {
  4755.  /*
  4756.      Get chars, then check scan codes and return our own values
  4757.  */
  4758.      KBDKEYINFO kbciKeyInfo;
  4759.  
  4760.      /*
  4761.          Wait for characters
  4762.      */
  4763.      KbdCharIn(&kbciKeyInfo, IO_WAIT, 0);
  4764.  
  4765.      switch (kbciKeyInfo.chScan) {
  4766.          case ESC:                         /* escape */
  4767.          case LINE_UP:
  4768.          case LINE_DOWN:
  4769.          case PAGE_UP:
  4770.          case PAGE_DOWN:
  4771.          case HOME_KEY:
  4772.          case END_KEY:
  4773.              return kbciKeyInfo.chScan; break;
  4774.          default:
  4775.             return((CHAR) NULL); break;
  4776.      }
  4777.  }
  4778.  
  4779.  
  4780.  CALC.C
  4781.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CALC\CALC.C
  4782.  
  4783.  /****************************** Module Header *******************************
  4784.  /*
  4785.  /* Module Name:  calc.c - Calc application
  4786.  /*
  4787.  /* OS/2 Presentation Manager version of Calc, ported from Windows version
  4788.  /*
  4789.  /* Created by Microsoft Corporation, 1987
  4790.  /*
  4791.  /****************************************************************************
  4792.  
  4793.  #define INCL_WININPUT
  4794.  #define INCL_WINPOINTERS
  4795.  #define INCL_WINMENUS
  4796.  #define INCL_WINSYS
  4797.  #define INCL_WINCLIPBOARD
  4798.  #define INCL_GPIPRIMITIVES
  4799.  #define INCL_GPIBITMAPS
  4800.  #define INCL_GPILCIDS
  4801.  #define INCL_DEV
  4802.  #define INCL_ERRORS
  4803.  #define INCL_DOSPROCESS
  4804.  #define INCL_DOSSEMAPHORES
  4805.  #define INCL_DOSNLS
  4806.  #include <os2.h>
  4807.  #include <string.h>
  4808.  #include <stdlib.h>
  4809.  #include <stdio.h>
  4810.  #include "calc.h"
  4811.  
  4812.  /****************************************************************************
  4813.  /*
  4814.  /*  GLOBAL VARIABLES
  4815.  /*
  4816.  /****************************************************************************
  4817.  
  4818.  CHAR  chLastKey, chCurrKey;
  4819.  CHAR  szreg1[20], szreg2[20], szmem[20], szregx[20];
  4820.  CHAR  szTitle[30], szErrorString[20], szPlusMinus[2];
  4821.  SHORT sCharWidth, sCharHeight;
  4822.  extern BOOL fError;
  4823.  BOOL  fValueInMemory = FALSE;
  4824.  BOOL  fMDown = FALSE;                       /* TRUE iff 'm' key depressed  */
  4825.  UCHAR uchMScan = 0;                       /* scan code for 'm' key       */
  4826.  
  4827.  #define TOLOWER(x)   ( (((x) >= 'A') && ((x) <= 'Z')) ? (x)|0x20 : (x))
  4828.  #define WIDTHCONST  28
  4829.  #define CXCHARS     37
  4830.  #define CYCHARS     13
  4831.  
  4832.  HAB hab;
  4833.  HDC hdcLocal;                            /* Local used for button bitmap */
  4834.  HPS hpsLocal;
  4835.  HDC hdcSqr;                            /* Sqr used for square-root bitmap */
  4836.  HPS hpsSqr;
  4837.  HBITMAP hbmLocal, hbmSqr;
  4838.  HMQ  hmqCalc;
  4839.  HWND hwndCalc, hwndMenu;
  4840.  HWND hwndCalcFrame;
  4841.  HPS  hpsCalc;
  4842.  HDC  hdcCalc;
  4843.  HPOINTER hptrFinger;
  4844.  
  4845.  DEVOPENSTRUC dop =                    /* used by DevOpenDC */
  4846.  {
  4847.      NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL
  4848.  };
  4849.  
  4850.  static char achKeys[25] =               /* keyboard keys */
  4851.  {
  4852.      '\271', '0', '.', '\261', '+', '=',
  4853.      '\272', '1', '2', '3', '-', 'c',
  4854.      '\273', '4', '5', '6', '*', '%',
  4855.      '\274', '7', '8', '9', '/', 'q',
  4856.      NULL
  4857.  };
  4858.  
  4859.  static CHAR achDKeys[25] =    /* 4th key is plusminus */
  4860.  {
  4861.      ' ', '0', '.', '+', '+', '=',
  4862.      ' ', '1', '2', '3', '-', 'C',
  4863.      ' ', '4', '5', '6', '*', '%',
  4864.      ' ', '7', '8', '9', '/', ' ',
  4865.      NULL
  4866.  };
  4867.  
  4868.  /****************************************************************************
  4869.  /*
  4870.  /*  PROCEDURE DECLARATIONS
  4871.  /*
  4872.  /****************************************************************************
  4873.  
  4874.  VOID FarStrcpy( PSZ, PSZ);
  4875.  MPARAM EXPENTRY AboutDlgProc( HWND, USHORT, MPARAM, MPARAM);
  4876.  BOOL CalcInit(VOID);
  4877.  VOID CalcPaint( HWND, HPS);
  4878.  VOID CalcTextOut( HPS, INT, INT, PCH, INT);
  4879.  MRESULT EXPENTRY CalcWndProc( HWND, USHORT, MPARAM, MPARAM);
  4880.  VOID cdecl main(VOID);
  4881.  VOID DataXCopy( VOID);
  4882.  VOID DataXPaste( VOID);
  4883.  VOID DrawNumbers( HPS);
  4884.  VOID Evaluate(BYTE);
  4885.  BOOL FlashSqr( HPS, PWPOINT);
  4886.  VOID FlipKey( HPS, INT, INT);
  4887.  VOID FrameKey( HPS, INT, INT);
  4888.  VOID InitCalc( VOID);
  4889.  BOOL InterpretChar( CHAR);
  4890.  VOID ProcessKey( PWPOINT);
  4891.  BOOL PSInit( VOID);
  4892.  CHAR Translate( PWPOINT);
  4893.  VOID UpdateDisplay( VOID);
  4894.  
  4895.  
  4896.  /****************************************************************************
  4897.  /****************************************************************************
  4898.  VOID CalcTextOut( hps, iX, iY, pch, iCount)
  4899.  
  4900.  HPS hps;
  4901.  INT iX, iY;
  4902.  PCH pch;
  4903.  INT iCount;
  4904.  {
  4905.      POINTL ptl;
  4906.  
  4907.      ptl.x = iX;
  4908.      ptl.y = iY;
  4909.  
  4910.      GpiSetColor( hps, CLR_BLACK);
  4911.      GpiCharStringAt( hps, (PPOINTL)&ptl, (LONG)iCount, (PSZ)pch);
  4912.  }
  4913.  
  4914.  
  4915.  /****************************************************************************
  4916.  /* Write the appropriate number or error string to the display area
  4917.  /* and mark memory-in-use if appropriate.
  4918.  /****************************************************************************
  4919.  VOID
  4920.  UpdateDisplay()
  4921.  {
  4922.      RECTL rcl;
  4923.  
  4924.      rcl.xLeft = (6 * sCharWidth);
  4925.      rcl.yBottom = 1050 * sCharHeight / 100;
  4926.      rcl.xRight = rcl.xLeft + (12 * sCharWidth);
  4927.      rcl.yTop = rcl.yBottom + (3 * sCharHeight) / 2;
  4928.  
  4929.      WinFillRect( hpsCalc, &rcl, CLR_WHITE);         /* paint display area whi
  4930.      if( fError)
  4931.          WinDrawText( hpsCalc
  4932.                     , -1
  4933.                     , szErrorString
  4934.                     , &rcl
  4935.                     , CLR_BLACK
  4936.                     , CLR_WHITE
  4937.                     , DT_RIGHT | DT_VCENTER );
  4938.      else
  4939.          WinDrawText( hpsCalc
  4940.                     , -1
  4941.                     , szreg1
  4942.                     , &rcl
  4943.                     , CLR_BLACK
  4944.                     , CLR_WHITE
  4945.                     , DT_RIGHT | DT_VCENTER );
  4946.  
  4947.      if (fValueInMemory)                 /* little black square shows mem use
  4948.      {
  4949.          rcl.xLeft = (6 * sCharWidth);
  4950.          rcl.yBottom = 1050 * sCharHeight / 100;
  4951.          rcl.xRight = rcl.xLeft + (sCharWidth / 2);
  4952.          rcl.yTop = rcl.yBottom + (sCharHeight / 2);
  4953.          WinFillRect( hpsCalc, &rcl, CLR_BLACK);
  4954.      }
  4955.  }
  4956.  
  4957.  
  4958.  /****************************************************************************
  4959.  /*  Display helpful info
  4960.  /****************************************************************************
  4961.  MPARAM EXPENTRY
  4962.  AboutDlgProc( hwnd, msg, mp1, mp2)
  4963.  
  4964.  HWND   hwnd;
  4965.  USHORT msg;
  4966.  MPARAM mp1;
  4967.  MPARAM mp2;
  4968.  {
  4969.      if (msg == WM_COMMAND)
  4970.      {
  4971.          WinDismissDlg(hwnd, TRUE);
  4972.          return(MPFROMSHORT(TRUE));
  4973.      }
  4974.      else return(WinDefDlgProc( hwnd, msg, mp1, mp2));
  4975.  }
  4976.  
  4977.  
  4978.  /****************************************************************************
  4979.  /*  General initialization
  4980.  /****************************************************************************
  4981.  BOOL
  4982.  CalcInit()
  4983.  {
  4984.      hab = WinInitialize( NULL);
  4985.  
  4986.      hmqCalc = WinCreateMsgQueue( hab, 0);
  4987.      if( !hmqCalc)
  4988.          return(FALSE);
  4989.  
  4990.      WinLoadString( NULL, NULL, 1, 30, (PSZ)szTitle);
  4991.      WinLoadString( NULL, NULL, 2, 20, (PSZ)szErrorString);
  4992.      WinLoadString( NULL, NULL, 3, 2, (PSZ)szPlusMinus);
  4993.  
  4994.      if (!WinRegisterClass( hab, szTitle, CalcWndProc, CS_SIZEREDRAW, 0))
  4995.          return(FALSE);
  4996.  
  4997.      hptrFinger = WinLoadPointer( HWND_DESKTOP, (HMODULE)NULL, IDP_FINGER);
  4998.  
  4999.      InitCalc();                         /* arithmetic initialization */
  5000.  
  5001.      return(TRUE);
  5002.  }
  5003.  
  5004.  /****************************************************************************
  5005.  /*  main procedure
  5006.  /****************************************************************************
  5007.  VOID cdecl
  5008.  main()
  5009.  {
  5010.      QMSG  qmsg;
  5011.      ULONG ulFCF;
  5012.  
  5013.      if (!CalcInit()) {                            /* general initialization *
  5014.          WinAlarm(HWND_DESKTOP, WA_ERROR);
  5015.          goto exit;
  5016.      }
  5017.  
  5018.      if (!PSInit()) {                            /* presentation spaces & bitm
  5019.          WinAlarm(HWND_DESKTOP, WA_ERROR);
  5020.          goto exit;
  5021.      }
  5022.  
  5023.      ulFCF = FCF_STANDARD & ~(LONG)(FCF_SIZEBORDER | FCF_MAXBUTTON);
  5024.      hwndCalcFrame = WinCreateStdWindow( HWND_DESKTOP
  5025.                                        , WS_VISIBLE | FS_BORDER
  5026.                                        , &ulFCF
  5027.                                        , szTitle
  5028.                                        , NULL
  5029.                                        , 0L
  5030.                                        , NULL
  5031.                                        , IDR_CALC
  5032.                                        , &hwndCalc);
  5033.  
  5034.      WinSetWindowPos( hwndCalcFrame
  5035.                     , (HWND)NULL
  5036.                     , 2
  5037.                     , 2
  5038.                     , CXCHARS * sCharWidth
  5039.                     , CYCHARS * sCharHeight
  5040.                               + (SHORT)WinQuerySysValue( HWND_DESKTOP
  5041.                                                        , SV_CYTITLEBAR )
  5042.                               + (SHORT)WinQuerySysValue( HWND_DESKTOP
  5043.                                                        , SV_CYMENU )
  5044.                     , SWP_MOVE | SWP_SIZE );
  5045.  
  5046.      while (WinGetMsg( hab, &qmsg, NULL, 0, 0))
  5047.          WinDispatchMsg( hab, &qmsg);
  5048.  
  5049.  exit:                                            /* clean up */
  5050.      if (hdcSqr)                             /* square-root bitmap */
  5051.      {
  5052.          GpiDestroyPS( hpsSqr);
  5053.          if (hbmSqr)
  5054.              GpiDeleteBitmap( hbmSqr);
  5055.      }
  5056.  
  5057.      if (hdcLocal)                            /* keypad button */
  5058.      {
  5059.          GpiDestroyPS( hpsLocal);
  5060.          if (hbmLocal)
  5061.              GpiDeleteBitmap( hbmLocal);
  5062.      }
  5063.  
  5064.      WinDestroyWindow(hwndCalcFrame);
  5065.  
  5066.      WinDestroyMsgQueue(hmqCalc);
  5067.      WinTerminate(hab);
  5068.  
  5069.      DosExit(EXIT_PROCESS, 0);                    /* exit without error */
  5070.  }
  5071.  
  5072.  
  5073.  /****************************************************************************
  5074.  /* Calc Window Procedure
  5075.  /****************************************************************************
  5076.  MRESULT EXPENTRY
  5077.  CalcWndProc(hwnd, msg, mp1, mp2)
  5078.  
  5079.  HWND        hwnd;
  5080.  USHORT        msg;
  5081.  MPARAM        mp1;
  5082.  MPARAM        mp2;
  5083.  {
  5084.      HPS     hps;
  5085.      RECTL   rclPaint;
  5086.      WPOINT  wpt;
  5087.      BOOL    fClip;
  5088.      USHORT  usFmtInfo;
  5089.      RECTL   rcl;
  5090.      SIZEL   sizl;
  5091.  
  5092.      switch (msg)
  5093.      {
  5094.      case WM_CREATE:
  5095.          hdcCalc = WinOpenWindowDC( hwnd);
  5096.          WinQueryWindowRect( hwnd, &rcl);
  5097.          sizl.cx = rcl.xRight - rcl.xLeft;
  5098.          sizl.cy = rcl.yTop - rcl.yBottom;
  5099.          hpsCalc = GpiCreatePS( hab
  5100.                               , hdcCalc
  5101.                               , &sizl
  5102.                               , GPIA_ASSOC | PU_PELS );
  5103.          break;
  5104.  
  5105.      case WM_DESTROY:
  5106.          WinDestroyPointer(hptrFinger);
  5107.          GpiDestroyPS( hpsSqr);
  5108.          GpiDeleteBitmap( hbmSqr);
  5109.          GpiDestroyPS( hpsLocal);
  5110.          GpiDeleteBitmap( hbmLocal);
  5111.          break;
  5112.  
  5113.      case WM_INITMENU:
  5114.          fClip = FALSE;
  5115.          if (WinOpenClipbrd( hab))
  5116.          {
  5117.              fClip = WinQueryClipbrdFmtInfo( hab, CF_TEXT, &usFmtInfo);
  5118.              WinCloseClipbrd( hab);
  5119.          }
  5120.          WinSendMsg((HWND)mp2, MM_SETITEMATTR,
  5121.                     (MPARAM) MAKELONG(CMD_PASTE, TRUE),
  5122.                     (MPARAM) MAKELONG(MIA_DISABLED, fClip ? 0 : MIA_DISABLED))
  5123.          break;
  5124.  
  5125.      case WM_PAINT:
  5126.          hps = WinBeginPaint(hwnd, NULL, &rclPaint);
  5127.          CalcPaint( hwnd, hps);                            /* re-draw calculat
  5128.          WinEndPaint(hps);
  5129.          break;
  5130.  
  5131.      case WM_COMMAND:
  5132.          if (fError)
  5133.              break;
  5134.          switch(LOUSHORT(mp1))
  5135.          {
  5136.          case CMD_COPY:
  5137.              DataXCopy();                    /* copy to clipboard */
  5138.              break;
  5139.          case CMD_PASTE:
  5140.              DataXPaste();                    /* paste from clipboard */
  5141.              break;
  5142.          case CMD_EXIT:
  5143.              WinPostMsg( hwndCalcFrame, WM_QUIT, 0L, 0L);
  5144.              break;
  5145.          case CMD_ABOUT:
  5146.              WinDlgBox( HWND_DESKTOP
  5147.                       , hwndCalcFrame
  5148.                       , (PFNWP)AboutDlgProc
  5149.                       , NULL
  5150.                       , 1
  5151.                       , (PSZ)NULL );
  5152.              break;
  5153.          }
  5154.          break;
  5155.  
  5156.      case WM_CLOSE:
  5157.          WinPostMsg(hwndCalcFrame, WM_QUIT, 0L, 0L);
  5158.          break;
  5159.  
  5160.      case WM_MOUSEMOVE:
  5161.          WinSetPointer( HWND_DESKTOP, hptrFinger);
  5162.          break;
  5163.  
  5164.      case WM_BUTTON1DOWN:
  5165.          wpt.x = LOUSHORT(mp1);
  5166.          wpt.y = HIUSHORT(mp1);
  5167.          ProcessKey( &wpt);
  5168.          goto dwp;
  5169.          break;
  5170.  
  5171.      case WM_CHAR:
  5172.          if (SHORT1FROMMP(mp1) & KC_KEYUP)
  5173.          {
  5174.              if (CHAR4FROMMP(mp1) == uchMScan)
  5175.                     fMDown = FALSE;                 /* 'm' key went up */
  5176.          }
  5177.          else
  5178.          {
  5179.                  if (SHORT1FROMMP(mp1) & KC_CHAR)
  5180.        {
  5181.               if (InterpretChar((UCHAR)SHORT1FROMMP(mp2)))
  5182.                    {
  5183.                                  UpdateDisplay();
  5184.                    }
  5185.               else
  5186.                    {
  5187.                                    if (((UCHAR)SHORT1FROMMP(mp2)== 'm') || ((U
  5188.                              {
  5189.                                          uchMScan = CHAR4FROMMP(mp1);
  5190.                                          fMDown = TRUE;
  5191.                              }
  5192.          }
  5193.                  }
  5194.          }
  5195.          break;
  5196.  
  5197.      case WM_ACTIVATE:
  5198.          if (HIUSHORT(mp1))
  5199.              WinSetFocus( HWND_DESKTOP, hwndCalc);
  5200.          break;
  5201.  
  5202.      case WM_SETFOCUS:
  5203.          if ((HWNDFROMMP(mp1)==hwndCalc) && !mp2);
  5204.              fMDown = FALSE;                        /* since we are losing foc
  5205.          break;
  5206.  
  5207.  dwp:
  5208.      default:
  5209.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  5210.          break;
  5211.      }
  5212.      return(0L);
  5213.  }
  5214.  
  5215.  
  5216.  /****************************************************************************
  5217.  /*  translate & interpret keys (ie. locate in logical keyboard)
  5218.  /****************************************************************************
  5219.  BOOL
  5220.  InterpretChar( ch)
  5221.  
  5222.  CHAR ch;
  5223.  {
  5224.      BOOL fDone;
  5225.      NPCH pchStep;
  5226.      INT  i;
  5227.  
  5228.      fDone = FALSE;
  5229.      pchStep = achKeys;
  5230.      switch (ch)
  5231.      {
  5232.      case 'n':
  5233.          ch = szPlusMinus[0];
  5234.          break;
  5235.      case 27:                        /* xlate Escape into 'c' */
  5236.          ch = 'c';
  5237.          break;
  5238.      case '\r':                      /* xlate Enter into '=' */
  5239.          ch = '=';
  5240.          break;
  5241.      }
  5242.  
  5243.      if (fMDown)                     /* Do memory keys */
  5244.      {
  5245.          switch (ch)
  5246.          {
  5247.          case 'c':
  5248.          case 'C':
  5249.              ch = '\274';
  5250.              break;
  5251.          case 'r':
  5252.          case 'R':
  5253.              ch = '\273';
  5254.              break;
  5255.          case '+':
  5256.              ch = '\272';
  5257.              break;
  5258.          case '-':
  5259.              ch = '\271';
  5260.              break;
  5261.          }
  5262.      }
  5263.  
  5264.      while (!fDone && *pchStep)
  5265.      {
  5266.          if ((CHAR) *pchStep++ == ch)
  5267.              fDone = TRUE;                /* char found in logical keyboard */
  5268.      }
  5269.      if (fDone)
  5270.      {
  5271.          chLastKey = chCurrKey;
  5272.          i = pchStep - achKeys - 1;
  5273.          FlipKey( hpsCalc, i/6, i%6);
  5274.          Evaluate( achKeys[i]);
  5275.      }
  5276.      return (fDone);
  5277.  }
  5278.  
  5279.  
  5280.  /****************************************************************************
  5281.  /*  briefly reverse the shading on one of the keys
  5282.  /****************************************************************************
  5283.  VOID
  5284.  FlipKey( hps, iRow, iCol)
  5285.  
  5286.  HPS hps;
  5287.  INT iRow, iCol;
  5288.  {
  5289.      RECTL rcl;
  5290.  
  5291.      rcl.xLeft = (iCol * 6 * sCharWidth) + (14 * sCharWidth / 10);
  5292.      rcl.yBottom = (165 * sCharHeight / 100) + (2 * iRow * sCharHeight);
  5293.      rcl.xRight = rcl.xLeft + (11 * sCharWidth / 3);
  5294.      rcl.yTop = rcl.yBottom + (7 * sCharHeight / 4);
  5295.      WinInvertRect( hps, &rcl);
  5296.      DosSleep( 50L);
  5297.      WinInvertRect( hps, &rcl);
  5298.  }
  5299.  
  5300.  
  5301.  /****************************************************************************
  5302.  /*  compute whether a point is over a button and flash the button if so
  5303.  /****************************************************************************
  5304.  BOOL
  5305.  FlashSqr( hps, pwpt)
  5306.  
  5307.  HPS         hps;
  5308.  PWPOINT  pwpt;
  5309.  {
  5310.      INT  iRow, iCol;
  5311.      BOOL fDone;
  5312.  
  5313.      /* find x range */
  5314.      fDone = FALSE;
  5315.      iCol = 0;
  5316.      iRow = 3;
  5317.      while (!fDone && iCol<6)
  5318.      {
  5319.          if (pwpt->x <        (iCol * 6 * sCharWidth)
  5320.                         + (14 * sCharWidth / 10)
  5321.                         + (11*sCharWidth/3)         )
  5322.          {
  5323.              if (pwpt->x > (iCol * 6 * sCharWidth) + (14 * sCharWidth / 10))
  5324.                  fDone = TRUE;
  5325.              else
  5326.                  return FALSE;
  5327.          }
  5328.          else
  5329.              iCol++;
  5330.      }
  5331.      if (!fDone)
  5332.          return FALSE;
  5333.      fDone = FALSE;
  5334.      while (!fDone && iRow >= 0)
  5335.      {
  5336.          if (pwpt->y > ((165 * sCharHeight / 100) + (2 * iRow * sCharHeight)))
  5337.          {
  5338.              if (pwpt->y <   (165 * sCharHeight / 100)
  5339.                             + (2 * iRow * sCharHeight)
  5340.                             + (7 * sCharHeight / 4)     )
  5341.                  fDone = TRUE;
  5342.              else
  5343.                  return FALSE;
  5344.          }
  5345.          else
  5346.              iRow--;
  5347.      }
  5348.      if (!fDone)
  5349.          return FALSE;
  5350.      pwpt->x = iCol;
  5351.      pwpt->y = iRow;
  5352.      FlipKey( hps, iRow, iCol);
  5353.      return TRUE;
  5354.  }
  5355.  
  5356.  
  5357.  /****************************************************************************
  5358.  /*  which key is point on?
  5359.  /****************************************************************************
  5360.  CHAR
  5361.  Translate( pwpt)
  5362.  
  5363.  PWPOINT pwpt;
  5364.  {
  5365.      return( achKeys[ pwpt->y * 6 + pwpt->x]);
  5366.  }
  5367.  
  5368.  
  5369.  /****************************************************************************
  5370.  /*  invoke flashing, point-to-key translation, and result-display update
  5371.  /****************************************************************************
  5372.  VOID
  5373.  ProcessKey( pwpt)
  5374.  
  5375.  PWPOINT pwpt;
  5376.  {
  5377.      BOOL fFlashed;
  5378.  
  5379.      chLastKey = chCurrKey;
  5380.      fFlashed = FlashSqr( hpsCalc, pwpt);
  5381.  
  5382.      if (fFlashed)
  5383.          Evaluate( (BYTE)Translate( pwpt));
  5384.      UpdateDisplay();
  5385.  }
  5386.  
  5387.  
  5388.  /****************************************************************************
  5389.  /*  draw a blank key
  5390.  /****************************************************************************
  5391.  VOID
  5392.  FrameKey(hps, iRow, iCol)
  5393.  
  5394.  HPS hps;
  5395.  INT iRow, iCol;
  5396.  {
  5397.      POINTL aptl[3];
  5398.  
  5399.      aptl[0].x = (iCol * 6 * sCharWidth) + (14 * sCharWidth / 10);
  5400.      aptl[0].y = (165 * sCharHeight / 100) + (2 * iRow * sCharHeight);
  5401.      aptl[1].x = (11 * sCharWidth / 3) + (aptl[0].x);
  5402.      aptl[1].y = (7 * sCharHeight / 4) + (aptl[0].y);
  5403.      aptl[2].x = 0;
  5404.      aptl[2].y = 0;
  5405.      GpiBitBlt( hps, hpsLocal, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  5406.  }
  5407.  
  5408.  
  5409.  /****************************************************************************
  5410.  /*  draw the keys and fill in numbers
  5411.  /****************************************************************************
  5412.  VOID
  5413.  DrawNumbers(hps)
  5414.  
  5415.  HPS hps;
  5416.  {
  5417.      INT iRow, iCol;
  5418.  
  5419.      /* Draw the keys and fill in the numbers we can */
  5420.      for (iRow = 0; iRow < 4; iRow++)
  5421.      {
  5422.          for (iCol = 0; iCol < 6; iCol++)
  5423.          {
  5424.              FrameKey( hps, iRow, iCol);
  5425.              CalcTextOut( hps
  5426.                         ,   (iCol * 6 * sCharWidth)
  5427.                           + (WIDTHCONST * sCharWidth / 10)
  5428.                         , (iRow + 1) * 2 * sCharHeight
  5429.                         , (PSZ)(achDKeys + (iRow * 6) + iCol)
  5430.                         , 1 );
  5431.          }
  5432.      }
  5433.  }
  5434.  
  5435.  
  5436.  /****************************************************************************
  5437.  /*  redraw the whole calculator
  5438.  /****************************************************************************
  5439.  VOID
  5440.  CalcPaint( hwnd, hps)
  5441.  
  5442.  HWND hwnd;
  5443.  HPS  hps;
  5444.  {
  5445.      RECTL      rclDst;
  5446.      CHARBUNDLE cbnd;
  5447.      INT        iX, iY;
  5448.  
  5449.      WinQueryWindowRect( hwnd, &rclDst);
  5450.      WinFillRect( hps, &rclDst, CLR_GREEN);
  5451.  
  5452.      DrawNumbers(hps);
  5453.      CalcTextOut(hps, iX = (11 * sCharWidth / 5) + 1, iY = 2 * sCharHeight,
  5454.                 (PSZ)"M-", 2);
  5455.      CalcTextOut(hps, iX, iY + 2 * sCharHeight, (PSZ)"M+", 2);
  5456.      CalcTextOut(hps, iX, iY + 4 * sCharHeight, (PSZ)"MR", 2);
  5457.      CalcTextOut(hps, iX, iY + 6 * sCharHeight, (PSZ)"MC", 2);
  5458.  
  5459.      /* Draw the minus of the plus/minus button */
  5460.      cbnd.usBackMixMode = FM_LEAVEALONE;
  5461.      GpiSetAttrs( hps, PRIM_CHAR, CBB_BACK_MIX_MODE, 0L, &cbnd);
  5462.      iX =  (3 * 6 * sCharWidth) + (WIDTHCONST * sCharWidth / 10);
  5463.      CalcTextOut( hps, iX, iY + sCharHeight / 4, (PSZ)"_", 1);
  5464.  
  5465.      /* Draw the square root bitmap */
  5466.      rclDst.xLeft = 160 * sCharWidth / 5;
  5467.      rclDst.yBottom = 31 * sCharHeight / 4;
  5468.      rclDst.xRight = rclDst.xLeft + 2 * sCharWidth;
  5469.      rclDst.yTop = rclDst.yBottom + (3 * sCharHeight / 2);
  5470.      WinDrawBitmap( hps
  5471.                   , hbmSqr
  5472.                   , NULL
  5473.                   , (PPOINTL)&rclDst
  5474.                   , CLR_WHITE
  5475.                   , CLR_BLACK
  5476.                   , DBM_STRETCH );
  5477.  
  5478.      UpdateDisplay();
  5479.  }
  5480.  
  5481.  
  5482.  /****************************************************************************
  5483.  /*  initialize the bitmaps for a blank key and for the square-root sign
  5484.  /****************************************************************************
  5485.  BOOL
  5486.  PSInit()
  5487.  {
  5488.      HPS              hps;
  5489.      FONTMETRICS      fm;
  5490.      POINTL             ptl;
  5491.      SIZEL             sizl;
  5492.      BITMAPINFOHEADER bmp;
  5493.      POINTL             aptl[4];
  5494.      LONG             alCaps[2];
  5495.  
  5496.      /************************************************************************
  5497.      /*        compute the units of horizontal and vertical distance based on
  5498.      /************************************************************************
  5499.      hps = WinGetPS( HWND_DESKTOP);
  5500.      GpiQueryFontMetrics( hps, (LONG)sizeof(FONTMETRICS), &fm);
  5501.      sCharHeight = (SHORT)(fm.lEmHeight); /* avg height of uppercase character
  5502.      sCharWidth        = (SHORT)(fm.lEmInc);         /* usually 'M' increment
  5503.      WinReleasePS( hps);
  5504.  
  5505.      /************************************************************************
  5506.      /*        prepare the square root bitmap
  5507.      /************************************************************************
  5508.      hdcSqr = DevOpenDC( hab, OD_MEMORY, "*", 3L, (PDEVOPENDATA)&dop, NULL);
  5509.      if( !hdcSqr)
  5510.          return(FALSE);
  5511.  
  5512.      sizl.cx = sizl.cy = 0L;
  5513.      hpsSqr = GpiCreatePS( hab
  5514.                          , hdcSqr
  5515.                          , &sizl
  5516.                          , PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  5517.      hbmSqr = GpiLoadBitmap( hpsSqr, NULL, IDB_SQR, 0L, 0L);
  5518.  
  5519.      /************************************************************************
  5520.      /*        prepare the bitmap of a blank key
  5521.      /************************************************************************
  5522.      hdcLocal = DevOpenDC( hab, OD_MEMORY, "*", 3L, (PDEVOPENDATA)&dop, NULL);
  5523.      if( !hdcLocal)
  5524.          return(FALSE);
  5525.  
  5526.      sizl.cx = sizl.cy = 0L;
  5527.      hpsLocal = GpiCreatePS( hab
  5528.                            , hdcLocal
  5529.                            , &sizl
  5530.                            , PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  5531.      bmp.cbFix = 12;
  5532.      bmp.cx = 11 * sCharWidth / 3;
  5533.      bmp.cy = sCharHeight * 2;
  5534.      DevQueryCaps( hdcLocal, CAPS_COLOR_PLANES, 2L, alCaps);
  5535.      bmp.cPlanes = (USHORT)alCaps[0];
  5536.      bmp.cBitCount = (USHORT)alCaps[1];
  5537.      hbmLocal = GpiCreateBitmap( hpsLocal, &bmp, 0L, NULL, NULL);
  5538.      if( !hbmLocal )
  5539.          return(FALSE);
  5540.      GpiSetBitmap( hpsLocal, hbmLocal);
  5541.  
  5542.      aptl[0].x = aptl[0].y = 0;
  5543.      aptl[1].x = 11 * sCharWidth / 3;
  5544.      aptl[1].y = 7 * sCharHeight / 4;
  5545.      aptl[2].x = aptl[2].y = 0;
  5546.      aptl[3].x = aptl[1].x;
  5547.      aptl[3].y = aptl[1].y;
  5548.      GpiSetColor( hpsLocal, CLR_GREEN);            /* match the background to
  5549.      GpiBitBlt( hpsLocal, NULL, 2L, aptl, ROP_PATCOPY, BBO_IGNORE);
  5550.  
  5551.      /* Draw the rounded rect */
  5552.      ptl.x = 0;
  5553.      ptl.y = 0;
  5554.      GpiSetCurrentPosition( hpsLocal, &ptl);
  5555.      ptl.x = (11 * sCharWidth / 3) - 1;
  5556.      ptl.y = (7 * sCharHeight / 4) - 1;
  5557.      GpiSetColor( hpsLocal, CLR_WHITE);            /* white interior
  5558.      GpiBox( hpsLocal
  5559.            , DRO_FILL
  5560.            , &ptl
  5561.            , (LONG)sCharWidth
  5562.            , (LONG)(sCharHeight / 2) );
  5563.      ptl.x = 0;
  5564.      ptl.y = 0;
  5565.      GpiSetCurrentPosition( hpsLocal, &ptl);
  5566.      ptl.x = (11 * sCharWidth / 3) - 1;
  5567.      ptl.y = (7 * sCharHeight / 4) - 1;
  5568.      GpiSetColor( hpsLocal, CLR_BLACK);            /* black border
  5569.      GpiBox( hpsLocal
  5570.            , DRO_OUTLINE
  5571.            , &ptl
  5572.            , (LONG)sCharWidth
  5573.            , (LONG)(sCharHeight / 2) );
  5574.      return( TRUE);
  5575.  }
  5576.  
  5577.  
  5578.  CALCMATH.C
  5579.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CALC\CALCMATH.C
  5580.  
  5581.  /****************************** Module Header *******************************
  5582.  /*
  5583.  /* Module Name:  calcmath.c - Calc application
  5584.  /*
  5585.  /* OS/2 Presentation Manager version of Calc, ported from Windows version
  5586.  /*
  5587.  /* Created by Microsoft Corporation, 1987
  5588.  /*
  5589.  /****************************************************************************
  5590.  
  5591.  #define INCL_WINCLIPBOARD
  5592.  #include <os2.h>
  5593.  #include <string.h>
  5594.  #include <stdio.h>
  5595.  #include <stdlib.h>
  5596.  #include <math.h>
  5597.  
  5598.  extern BOOL fValueInMemory;
  5599.  extern CHAR chLastKey;
  5600.  extern CHAR szreg1[20], szreg2[20], szmem[20];
  5601.  extern HWND hwndCalc;
  5602.  extern CHAR szregx[];
  5603.  extern HAB  hab;
  5604.  BOOL   fReadNumber;
  5605.  CHAR   PendingOperation;
  5606.  BOOL   fFirstOperand, fError;
  5607.  CHAR   szresult[20];
  5608.  SEL    sel;
  5609.  
  5610.  #define tolower(x)   (((x) >= 'A') && ((x)<='Z')) ? (x) - 'A' + 'a' : (x)
  5611.  #define MAXINT        (double)999999999
  5612.  #define MININT (double)-999999999
  5613.  #define ABS(x)                (((x) >= (double)0) ? (x) : (-(x)))
  5614.  
  5615.  
  5616.  /****************************************************************************
  5617.  extern VOID UpdateDisplay( VOID);
  5618.  extern BOOL InterpretChar( CHAR);
  5619.  
  5620.  VOID AppendNumber( BYTE);
  5621.  VOID BinaryOperator( CHAR);
  5622.  VOID Clear( VOID);
  5623.  VOID DataXCopy( VOID);
  5624.  VOID DataXPaste( VOID);
  5625.  VOID Equilibrate( VOID);
  5626.  VOID Evaluate( BYTE);
  5627.  VOID FarStrcpy( PSZ, PSZ);
  5628.  NPCH ftoa( double);
  5629.  VOID InitCalc( VOID);
  5630.  VOID MClear( VOID);
  5631.  VOID MMinus( VOID);
  5632.  VOID MPlus( VOID);
  5633.  VOID Negate( VOID);
  5634.  VOID Number( CHAR);
  5635.  VOID Percent( VOID);
  5636.  VOID reverse( NPCH);
  5637.  VOID Simplify( VOID);
  5638.  VOID SquareRoot( VOID);
  5639.  
  5640.  
  5641.  /****************************************************************************
  5642.  VOID FarStrcpy( pszDest, pszSrc)
  5643.  PSZ  pszDest, pszSrc;
  5644.  {
  5645.      while( *pszDest++ = *pszSrc++);
  5646.  }
  5647.  
  5648.  /****************************************************************************
  5649.  VOID
  5650.  reverse( s)
  5651.  
  5652.  NPCH s;
  5653.  {
  5654.      CHAR ch;
  5655.      register INT iHead, iTail;
  5656.  
  5657.      for (iHead = 0, iTail = strlen(s) - 1; iHead<iTail; iHead++, iTail-- ) {
  5658.          ch = s[iHead];
  5659.          s[iHead] = s[iTail];
  5660.          s[iTail] = ch;
  5661.      }
  5662.  }
  5663.  
  5664.  /****************************************************************************
  5665.  NPCH
  5666.  ftoa( dblNum)
  5667.  
  5668.  double dblNum;
  5669.  {
  5670.      sprintf( szresult, "%.8f", dblNum );
  5671.      return (szresult);
  5672.  }
  5673.  
  5674.  
  5675.  /****************************************************************************
  5676.  VOID
  5677.  Negate()
  5678.  {
  5679.      CHAR sztemp[ 20 ];
  5680.  
  5681.      if (szreg1[0] ==  '-')
  5682.          strcpy(szreg1, (&szreg1[1]));                     /* get rid of minus
  5683.      else if (szreg1[0] != '0' || (strlen(szreg1) > 2)) { /* can't negate zero
  5684.               sztemp[0] = '-';
  5685.               strcpy(&sztemp[1], szreg1);
  5686.               strcpy(szreg1, sztemp);
  5687.           }
  5688.  }
  5689.  
  5690.  /****************************************************************************
  5691.  VOID
  5692.  Number( ch)
  5693.  
  5694.  CHAR ch;
  5695.  {
  5696.      register INT iLen, iSize;
  5697.  
  5698.      iSize = 9;
  5699.      if (szreg1[0] == '-') iSize++;
  5700.      if (strchr(szreg1, '.')) iSize++;
  5701.      iLen  = strlen(szreg1 );
  5702.      if (iLen == iSize) return;
  5703.      if (iLen == 1 && szreg1[0] == '0') iLen--;
  5704.      szreg1[ iLen ] = ch;
  5705.      szreg1[min(iLen + 1, 11)] = 0;
  5706.  }
  5707.  
  5708.  /****************************************************************************
  5709.  VOID
  5710.  AppendNumber ( b)
  5711.  
  5712.  BYTE b;
  5713.  {
  5714.      if (b == '.') {                    /*        if no decimal, add one at en
  5715.          if (!strchr(szreg1, '.'))
  5716.              strcat(szreg1, ".");
  5717.      }
  5718.      else if ( b == 0xb1 )
  5719.               Negate();
  5720.           else
  5721.               Number(b);
  5722.  }
  5723.  
  5724.  /****************************************************************************
  5725.  VOID
  5726.  Equilibrate()
  5727.  {
  5728.      double dblResult;
  5729.      double dblX1, dblX2;
  5730.  
  5731.      if (chLastKey == '=') return;
  5732.      dblResult = (double)atof(szreg1);
  5733.      dblX1 = (double)atof(szreg1);
  5734.      dblX2 = (double)atof(szreg2);
  5735.  
  5736.      switch (PendingOperation) {
  5737.          case '+':
  5738.              if (dblX2>(double)0) {            /* check for overflow */
  5739.                  if (dblX1>(double)0) {
  5740.                      if (dblX1 > (MAXINT - dblX2))
  5741.                          fError = TRUE;
  5742.                  }
  5743.              }
  5744.              else if (dblX2 < (double)0) {
  5745.                       if (dblX1 < (double)0) {
  5746.                           if ( dblX1 < (MININT - dblX2))
  5747.                               fError = TRUE;
  5748.                       }
  5749.                   }
  5750.              if (!fError)
  5751.                  dblResult = dblX2 + dblX1;
  5752.              break;
  5753.          case '-':
  5754.              if (dblX2 < (double)0) {
  5755.                  if (dblX1 > (double)0) {
  5756.                      if (dblX1 > (dblX2 - MININT))
  5757.                          fError = TRUE;
  5758.                  }
  5759.              }
  5760.              else if (dblX2 > (double)0) {
  5761.                      if (dblX1 < (double)0) {
  5762.                          if (dblX1 < (dblX2 - MAXINT))
  5763.                              fError = TRUE;
  5764.                      }
  5765.                   }
  5766.              if (!fError)
  5767.                  dblResult = dblX2 - dblX1;
  5768.              break;
  5769.          case '/':
  5770.              if (dblX1 == (double)0.0)
  5771.                  fError = TRUE;
  5772.              else if (dblX2 > (double)0) {
  5773.                       if (dblX1 > (double)0) {
  5774.                           if (dblX1 < (dblX2 / MAXINT))
  5775.                               fError = TRUE;
  5776.                       }
  5777.                       else {  /* dblX1 < 0 here */
  5778.                          if (dblX1 > (dblX2 / MININT))
  5779.                               fError = TRUE;
  5780.                       }
  5781.                   }
  5782.                   else {  /* dblX2 < 0 here */
  5783.                       if (dblX1 < (double)0) {
  5784.                           if (dblX1 > (dblX2 / MAXINT))
  5785.                               fError = TRUE;
  5786.                       }
  5787.                       else { /* dblX1 > 0 here */
  5788.                           if (dblX1 < (dblX2 / MININT))
  5789.                               fError = TRUE;
  5790.                       }
  5791.                   }
  5792.              if (!fError)
  5793.                  dblResult = dblX2 / dblX1;
  5794.              break;
  5795.          case '*':
  5796.              if (dblX1 == (double)0) return;
  5797.              if (ABS(dblX2) > (double)1) {
  5798.                  if (ABS(dblX1) > (double)1) {
  5799.                      if (ABS(dblX1) > (MAXINT / ABS(dblX2)))
  5800.                          fError = TRUE;
  5801.                      }
  5802.                  }
  5803.              if (!fError) dblResult = dblX2 * dblX1;
  5804.              break;
  5805.          }
  5806.      if (!fError) {
  5807.          strcpy(szreg1, ftoa((double)dblResult));
  5808.          strcpy( szreg2, szreg1 );
  5809.          }
  5810.      Simplify();
  5811.  }
  5812.  
  5813.  /****************************************************************************
  5814.  VOID
  5815.  SquareRoot()
  5816.  {
  5817.      double dblResult;
  5818.  
  5819.      dblResult = (double)atof(szreg1);
  5820.      if (dblResult < 0.0) {
  5821.          fError = TRUE;
  5822.          return;
  5823.      }
  5824.      if ((dblResult == 0.0) || ((chLastKey == 'q') && (dblResult == 1.0)))
  5825.          return;
  5826.      if ((dblResult < (double) 1.00000002) && (dblResult > (double) 1.0))
  5827.          dblResult = (double)1.0;
  5828.      else
  5829.          dblResult = sqrt(dblResult);
  5830.      strcpy( szreg1, ftoa((double)dblResult));
  5831.      if (atof( szreg1 ) == 0.0)
  5832.          strcpy(szreg1, "0.");
  5833.      Simplify();
  5834.  }
  5835.  
  5836.  /****************************************************************************
  5837.  VOID
  5838.  BinaryOperator( ch)
  5839.  
  5840.  CHAR ch;
  5841.  {
  5842.      if (fFirstOperand) {
  5843.          fFirstOperand = FALSE;
  5844.          strcpy(szreg2, szreg1);
  5845.      }
  5846.      else {
  5847.          Equilibrate();
  5848.      }
  5849.      PendingOperation = ch;
  5850.  }
  5851.  
  5852.  /****************************************************************************
  5853.  VOID
  5854.  Clear()
  5855.  {
  5856.      fReadNumber = FALSE;
  5857.      fFirstOperand = TRUE;
  5858.      strcpy(szreg1, "0.");
  5859.      if (fError || chLastKey == 'c'){
  5860.          strcpy(szreg2, "0.");
  5861.          PendingOperation = NULL;
  5862.      }
  5863.      fError = FALSE;
  5864.  }
  5865.  
  5866.  /****************************************************************************
  5867.  /* trash out trailing zeros, if a '.' is in the number
  5868.  /* and leading zeros in all cases.
  5869.  /****************************************************************************
  5870.  VOID
  5871.  Simplify()
  5872.  {
  5873.      register INT iLen, iCount;
  5874.      CHAR         achLocal[20];
  5875.  
  5876.      iCount = 0;
  5877.      strcpy(achLocal, szreg1);
  5878.      if (atof(achLocal) != 0.0) {
  5879.          while (achLocal[iCount++] == '0');
  5880.          strcpy(szreg1, &achLocal[iCount-1] );
  5881.      }
  5882.      if (strchr(szreg1, '.')) {
  5883.          iLen = strlen(szreg1);
  5884.          while (szreg1[--iLen] == '0');
  5885.          szreg1[min( iLen + 1, 11)] = 0; /* null terminate */
  5886.      }
  5887.  }
  5888.  
  5889.  
  5890.  /****************************************************************************
  5891.  VOID
  5892.  DataXPaste()
  5893.  {
  5894.      PSZ           psz;
  5895.      ULONG          ulText;
  5896.      register CHAR ch;
  5897.  
  5898.      if (WinOpenClipbrd( hab))
  5899.      {
  5900.          ulText = WinQueryClipbrdData( hab, CF_TEXT);
  5901.          if (ulText)
  5902.          {
  5903.              psz = MAKEP( (SEL)ulText, 0);
  5904.              while (*psz)
  5905.              {
  5906.                  ch = (CHAR) (tolower(*psz));
  5907.                  if (ch == 'm')
  5908.                  {
  5909.                      psz++;
  5910.                      switch (tolower(*psz))
  5911.                      {
  5912.                          case '-':
  5913.                              ch = '\271';
  5914.                              break;
  5915.                          case '+':
  5916.                              ch = '\272';
  5917.                              break;
  5918.                          case 'r':
  5919.                              ch = '\273';
  5920.                              break;
  5921.                          case 'c':
  5922.                              ch = '\274';
  5923.                              break;
  5924.                          default:
  5925.                              ch = ' ';
  5926.                              break;
  5927.                      }
  5928.                  }
  5929.                  psz++;
  5930.                  InterpretChar(ch);
  5931.                  UpdateDisplay();
  5932.              }
  5933.          }
  5934.      }
  5935.      WinCloseClipbrd( hab);
  5936.      InterpretChar('=');
  5937.      UpdateDisplay();
  5938.  }
  5939.  
  5940.  
  5941.  /****************************************************************************
  5942.  VOID
  5943.  DataXCopy()
  5944.  {
  5945.      PSZ  pszText;
  5946.  
  5947.      if (WinOpenClipbrd( hab))
  5948.      {
  5949.          WinEmptyClipbrd( hab);
  5950.          DosAllocSeg( 20, (SEL FAR *)&sel, SEG_GIVEABLE);
  5951.          if (sel == NULL) return;
  5952.          pszText = MAKEP(sel, 0);
  5953.          FarStrcpy( pszText, (PSZ)szreg1);
  5954.          WinSetClipbrdData( hab, (ULONG)sel, CF_TEXT, CFI_SELECTOR);
  5955.          WinCloseClipbrd( hab);
  5956.      }
  5957.  }
  5958.  
  5959.  
  5960.  /****************************************************************************
  5961.  VOID
  5962.  MPlus()
  5963.  {
  5964.      double dblX1, dblX2, dblResult;
  5965.  
  5966.      dblX2 = atof(szmem);
  5967.      dblX1 = atof(szreg1);
  5968.  
  5969.      if (dblX2>(double)0) {            /* check for overflow */
  5970.          if (dblX1>(double)0) {
  5971.              if (dblX1 > (MAXINT - dblX2))
  5972.                  fError = TRUE;
  5973.          }
  5974.      }
  5975.      else if (dblX2 < (double)0) {
  5976.               if (dblX1 < (double)0) {
  5977.                   if ( dblX1 < (MININT - dblX2))
  5978.                       fError = TRUE;
  5979.               }
  5980.           }
  5981.      if (!fError) {
  5982.          dblResult = dblX2 + dblX1;
  5983.          strcpy( szmem, ftoa((double)dblResult));
  5984.      }
  5985.      if (dblResult == (double)0.0)
  5986.           fValueInMemory = FALSE;
  5987.      else fValueInMemory = TRUE;
  5988.  }
  5989.  
  5990.  /****************************************************************************
  5991.  VOID
  5992.  MClear()
  5993.  {
  5994.       strcpy(szmem, "0.");
  5995.       fValueInMemory = FALSE;
  5996.  }
  5997.  
  5998.  
  5999.  /****************************************************************************
  6000.  VOID
  6001.  MMinus()
  6002.  {
  6003.      double dblX1, dblX2, dblResult;
  6004.  
  6005.      dblX2 = atof(szmem);
  6006.      dblX1 = atof(szreg1);
  6007.      if (dblX2 < (double)0) {
  6008.          if (dblX1 > (double)0) {
  6009.              if (dblX1 > (dblX2 - MININT))
  6010.                  fError = TRUE;
  6011.          }
  6012.      }
  6013.      else if (dblX2 > (double)0) {
  6014.              if (dblX1 < (double)0) {
  6015.                  if (dblX1 < (dblX2 - MAXINT))
  6016.                      fError = TRUE;
  6017.              }
  6018.           }
  6019.      if (!fError) {
  6020.          dblResult = dblX2 - dblX1;
  6021.          strcpy( szmem, ftoa((double)dblResult));
  6022.      }
  6023.      if (dblResult == (double)0.0)
  6024.           fValueInMemory = FALSE;
  6025.      else fValueInMemory = TRUE;
  6026.  }
  6027.  
  6028.  /****************************************************************************
  6029.  VOID
  6030.  Evaluate( bCommand)
  6031.  
  6032.  BYTE bCommand;
  6033.  {
  6034.      switch( bCommand ) {
  6035.          case '0': case '1': case '2': case '3': case '4': case '5':
  6036.          case '6': case '7': case '8': case '9': case '.': case 0xb1:
  6037.          case 'n': /* n = 'negate'  from keyboard */
  6038.              if ( fReadNumber )
  6039.                  AppendNumber( bCommand );
  6040.              else {
  6041.                        /* if starting a new number */
  6042.                  if (bCommand != 0xb1)
  6043.                      strcpy(szreg1, "0");
  6044.                  AppendNumber( bCommand );
  6045.              }
  6046.              if (bCommand != 0xb1)
  6047.                  fReadNumber = TRUE;
  6048.              break;
  6049.          case '+': case '-': case '/': case '*': case 'p':
  6050.              BinaryOperator(bCommand);
  6051.              fReadNumber = FALSE;
  6052.              break;
  6053.          case '=':
  6054.              fReadNumber = FALSE;
  6055.              Equilibrate();
  6056.              PendingOperation = NULL;
  6057.              break;
  6058.          case 'q':
  6059.              SquareRoot();
  6060.              fReadNumber = FALSE;
  6061.              break;
  6062.          case 0xBB:   /* MR */
  6063.              strcpy(szreg1, szmem);
  6064.              fReadNumber = FALSE;
  6065.              Simplify();
  6066.              break;
  6067.          case 0xBA: /* M+ */
  6068.              MPlus();
  6069.              fReadNumber = FALSE;
  6070.              Simplify();
  6071.              break;
  6072.          case 0xB9: /* M- */
  6073.              MMinus();
  6074.              fReadNumber = FALSE;
  6075.              Simplify();
  6076.              break;
  6077.          case 0xBC:
  6078.              MClear(); /* MC */
  6079.              break;
  6080.          case '%':
  6081.              Percent();
  6082.              fReadNumber = FALSE;
  6083.              break;
  6084.          case 'c':
  6085.              Clear();
  6086.              break;
  6087.          }
  6088.  }
  6089.  
  6090.  /****************************************************************************
  6091.  VOID
  6092.  Percent()
  6093.  {
  6094.      double dblX1, dblX2, dblResult;
  6095.  
  6096.      dblX1 = atof(szreg1) / 100.0;
  6097.      dblX2 = atof(szreg2);
  6098.      if (ABS(dblX2) > (double)1) {
  6099.          if (ABS(dblX1) > (double)1) {
  6100.              if (dblX1 > (MAXINT / dblX2))
  6101.                  fError = TRUE;
  6102.          }
  6103.      }
  6104.      if (!fError) {
  6105.          dblResult = dblX2 * dblX1;
  6106.          strcpy( szreg1, ftoa((double)dblResult));
  6107.      }
  6108.      Simplify();
  6109.  }
  6110.  
  6111.  /****************************************************************************
  6112.  VOID
  6113.  InitCalc()
  6114.  {
  6115.      fReadNumber = FALSE;
  6116.      fError = FALSE;
  6117.      fFirstOperand = TRUE;
  6118.      PendingOperation = 0;
  6119.      strcpy(szreg1, "0.");
  6120.      strcpy(szmem,  "0.");
  6121.  }
  6122.  
  6123.  
  6124.  CASCADE.C
  6125.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CASCADE\CASCADE.C
  6126.  
  6127.  #define INCL_PM
  6128.  #include <OS2.H>
  6129.  #include "Cascade.H"
  6130.  
  6131.  char szAppName[] = "Cascade";
  6132.  char szAppTitle[] = "Cascading Menu Example";
  6133.  
  6134.  HAB        hAB;
  6135.  HMQ        hmqMsgQueue;
  6136.  HWND        hWndMain,
  6137.          hWndFrame;
  6138.  
  6139.  int cdecl main()
  6140.  {
  6141.      QMSG    qmsg;
  6142.      ULONG   ctlData = FCF_STANDARD & ~FCF_ACCELTABLE;
  6143.  
  6144.      hAB = WinInitialize (0);
  6145.  
  6146.      hmqMsgQueue = WinCreateMsgQueue (hAB, 0);
  6147.  
  6148.      if (!WinRegisterClass (hAB,
  6149.                             szAppName,
  6150.                             WndProc,
  6151.                             CS_SYNCPAINT | CS_SIZEREDRAW,
  6152.                             0)) {
  6153.          return(0);
  6154.      }
  6155.  
  6156.      hWndFrame = WinCreateStdWindow ( HWND_DESKTOP,
  6157.                                      WS_VISIBLE,
  6158.                                      &ctlData,
  6159.                                      szAppName,
  6160.                                      NULL,
  6161.                                      0L,
  6162.                                      0,
  6163.                                      ID_RESOURCE,
  6164.                                      &hWndMain);
  6165.      WinSetWindowText (hWndFrame, szAppTitle);
  6166.      WinShowWindow (hWndFrame, TRUE);
  6167.  
  6168.      while ( WinGetMsg (hAB, &qmsg, NULL, 0, 0)) {
  6169.          WinDispatchMsg (hAB, &qmsg);
  6170.      }
  6171.  
  6172.      WinDestroyWindow   (hWndFrame);
  6173.      WinDestroyMsgQueue (hmqMsgQueue);
  6174.      WinTerminate       (hAB);
  6175.  }
  6176.  
  6177.  /*-------------------------------------------------------------------*/
  6178.  /*                                                                     */
  6179.  /*-------------------------------------------------------------------*/
  6180.  
  6181.  BOOL CheckAll (HWND hMenu, int item, BOOL check);
  6182.  BOOL CheckAll (HWND hMenu, int item, BOOL check)
  6183.  {
  6184.      int mPos,max,test;
  6185.      MENUITEM mi;
  6186.      char szText[20];
  6187.      MPARAM  mp1, mp2;
  6188.  
  6189.      max =(int) SHORT1FROMMR( WinSendMsg (hMenu, MM_QUERYITEMCOUNT, 0L, 0L) );
  6190.  
  6191.      for (mPos=0; mPos!=(int) max; mPos++) {
  6192.          test =(int) SHORT1FROMMR( WinSendMsg (hMenu, MM_ITEMIDFROMPOSITION, M
  6193.          WinSendMsg (hMenu, MM_QUERYITEMTEXT, MPFROM2SHORT(test,sizeof(szText)
  6194.          if (test == item) {
  6195.              mp1 = MPFROM2SHORT (test, TRUE);
  6196.              if (check)
  6197.                  mp2 = MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED);
  6198.              else
  6199.                  mp2 = MPFROM2SHORT(MIA_CHECKED, 0);
  6200.              WinPostMsg (hMenu, MM_SETITEMATTR, mp1, mp2);
  6201.              return TRUE;
  6202.          } else {
  6203.              WinSendMsg (hMenu, MM_QUERYITEM, MPFROM2SHORT(test,FALSE), (MPARA
  6204.              if (mi.hwndSubMenu) {
  6205.                  if (CheckAll(mi.hwndSubMenu, item, check)) {
  6206.                      mp1 = MPFROM2SHORT (test, TRUE);
  6207.                      if (check)
  6208.                          mp2 = MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED);
  6209.                      else
  6210.                          mp2 = MPFROM2SHORT(MIA_CHECKED, 0);
  6211.                      WinPostMsg (hMenu, MM_SETITEMATTR, mp1, mp2);
  6212.                      return TRUE;
  6213.                  }
  6214.  
  6215.              }
  6216.          }
  6217.      }
  6218.      return FALSE;
  6219.  }
  6220.  
  6221.  /*-------------------------------------------------------------------*/
  6222.  /*                                                                     */
  6223.  /*-------------------------------------------------------------------*/
  6224.  
  6225.  
  6226.  MRESULT EXPENTRY WndProc (hWnd, msg, mp1, mp2)
  6227.      HWND    hWnd;
  6228.      USHORT  msg;
  6229.      MPARAM  mp1, mp2;
  6230.  {
  6231.      HPS           hPS;
  6232.      HWND   hMenu;
  6233.      static int          prevFont = 0;
  6234.      int thisItem;
  6235.  
  6236.      switch (msg) {
  6237.  
  6238.          case WM_COMMAND:
  6239.              thisItem = SHORT1FROMMP(mp1);
  6240.              switch (thisItem) {
  6241.                  case IDM_ABOUT:
  6242.                      WinMessageBox (HWND_DESKTOP, hWnd,
  6243.                          "Sample PM Application",
  6244.                          szAppTitle, 1, MB_OK | MB_APPLMODAL | MB_MOVEABLE);
  6245.                      break;
  6246.                  default:
  6247.                      if ((thisItem >= IDM_FIRSTFONT) && (thisItem<= IDM_LASTFO
  6248.                          hMenu        = WinWindowFromID (
  6249.                                      WinQueryWindow (hWnd, QW_PARENT, FALSE),
  6250.                                      FID_MENU);
  6251.                          CheckAll (hMenu, prevFont, FALSE);
  6252.                          CheckAll (hMenu, thisItem, TRUE);
  6253.                          prevFont = thisItem;
  6254.                      } else {
  6255.                          DosBeep(600,60);
  6256.                      }
  6257.              }
  6258.              break;
  6259.  
  6260.          case WM_CLOSE:
  6261.              WinPostMsg (hWnd, WM_QUIT, 0L, 0L);
  6262.              break;
  6263.  
  6264.          case WM_ERASEBACKGROUND:
  6265.              return ((MRESULT) TRUE);
  6266.              break;
  6267.  
  6268.          case WM_PAINT:
  6269.              hPS = WinBeginPaint (hWnd, NULL, (PWRECT)NULL);
  6270.              WinEndPaint (hPS);
  6271.              break;
  6272.  
  6273.          default:
  6274.              return (WinDefWindowProc (hWnd, msg, mp1, mp2));
  6275.              break;
  6276.      }
  6277.      return 0L;
  6278.  }
  6279.  
  6280.  
  6281.  CHASER.C
  6282.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CHASER\CHASER.C
  6283.  
  6284.  /*  SWARM
  6285.   *  Created by Microsoft Corp. 1986
  6286.   *
  6287.   *  the idea behind this game is as follows:
  6288.   *
  6289.   *   You have a collection of objects in the center of the playing field
  6290.   *   that you are trying to protect (just one object in current version). You
  6291.   *   control your own movements with the mouse. A number of "chasers" start
  6292.   *   around the edges of the field and begin moving towards the objects
  6293.   *   you want to protect. If you move the mouse on top of a chaser and click
  6294.   *   the left button, the chaser will be killed and disappear from the screen
  6295.   *   But as you close in on the chaser, it will detect your presence and try
  6296.   *   to dodge you. Meanwhile the other chasers will continue to go after
  6297.   *   your objects. If one of the chasers reaches an object, it will begin
  6298.   *   dragging it away to the edge of the screen (currently the game just
  6299.   *   ends when the single object is reached). When all objects are dragged
  6300.   *   away, the game ends. If a chaser is killed while dragging an object, the
  6301.   *   object is left where it is and must be protected in place - player canno
  6302.   *   move objects. If you kill all the chasers, a new group of faster ones
  6303.   *   will be spawned (currently the speed is constant). Your score is how
  6304.   *   many chasers you can kill (no score currently kept), so there is no
  6305.   *   advantage in sitting on the object for long periods.
  6306.   *
  6307.   * Swarm demonstrates several capabilities of OS/2 and the philosphy behind
  6308.   * them.  This program is made of three components: Initialization, the
  6309.   * mouse driven thread and the attacker thread.  The attacker thread is
  6310.   * launched as many times as there are attackers in a game.  Launching
  6311.   * the attacker several times takes full advantage of the OS to schedule
  6312.   * resources.  The programmer can think of the problem as only one attacker.
  6313.   * The system handles multiple instances of the thread.
  6314.   *
  6315.   * As the main loop launches threads it puts an ID code into the thread's
  6316.   * stack.  The code is used to index into the universe data.
  6317.   *
  6318.   * A ram semaphore is used to control access to global data.
  6319.   *
  6320.   * This demonstration shows the use of the following OS/2 system calls:
  6321.   *
  6322.   * Tasking:               VIO API:              Mouse API:
  6323.   *
  6324.   *   DosSemRequest()         VioScrollUp()               MouOpen()
  6325.   *   DosSemClear()         VioWrtCellStr()       MouSetPtrPos()
  6326.   *   DosCreateThread()         VioSetCurType()       MouReadEventQue()
  6327.   *   DosExit()                 VioSetMode()
  6328.   *   DosSleep()
  6329.   */
  6330.  #include <os2def.h>
  6331.  #define INCL_DOSPROCESS
  6332.  #define INCL_DOSSEMAPHORES
  6333.  #include <bsedos.h>
  6334.  #define INCL_SUB
  6335.  #include <bsesub.h>
  6336.  #include <malloc.h>
  6337.  #undef NULL
  6338.  #include <stdio.h>
  6339.  
  6340.  #define  STACKSIZE  200
  6341.  
  6342.  #define  DANGERZONE  3
  6343.  
  6344.  #define  LONGNAP     500L
  6345.  #define  SHORTNAP    150L
  6346.  
  6347.   WAIT (-1L)                        /* Wait for ram Semaphore */
  6348.  
  6349.   CHASER    8                        /* Number of chasers */
  6350.  
  6351.   SCREEN_HEIGHT           24                /* Default screen size */
  6352.  #define  SCREEN_WIDTH           79
  6353.  
  6354.   GOAL univ[CHASER]                /* Macros for constant stuff */
  6355.  #define  ME univ[ID]
  6356.  #define  MOUSE univ[CHASER+1]
  6357.  
  6358.   ALIVE 1                        /* Flags for attackers/goal */
  6359.  #define  DEAD 0
  6360.  
  6361.  char   Chaser[2] = { 0xE8, 0x20 };   /* character and attribute */
  6362.  char        Prize[2] = { 0x03, 0x2C };   /* for our various objects */
  6363.  char        Blank[2] = { 0x20, 0x22 };
  6364.  char        Blood[2] = { 0x20, 0x44 };
  6365.  
  6366.  struct {                              /* Universe structure and array */
  6367.      int     row;                        /* univ[0] = chaser     */
  6368.      int     col;                        /* univ[n-1] = chaser     */
  6369.      int     state;                        /* univ[n] = GOAL */
  6370.  } univ[CHASER+1];                        /* univ[n+1]= MOUSE */
  6371.  
  6372.  short                ScreenHeight,                /* Screen attributes */
  6373.                  ScreenWidth;
  6374.  
  6375.  HMOU                Mouse;                        /* place for mouse handle *
  6376.  ULONG                Shortnap;                /* Sleep times for chasers */
  6377.  ULONG                Longnap;
  6378.  ULONG                Semaphore = 0;                /* Ram semaphore */
  6379.  
  6380.  struct _VIOCURSORINFO        NewCur;         /* struct for setting cursor typ
  6381.  struct _VIOCURSORINFO        OldCur;
  6382.  
  6383.  struct _VIOMODEINFO        modedata;        /* Data saves for VIO mode */
  6384.  struct _VIOMODEINFO        OldVioMode;
  6385.  
  6386.  /*
  6387.   * Define all procedures before main.
  6388.   */
  6389.  void Defender();
  6390.  void CleanUp();
  6391.  int InitGame();
  6392.  void chaserthread();
  6393.  int ParseCmdLine(int,char **);
  6394.  
  6395.  /*
  6396.   * main(ac,av)
  6397.   *
  6398.   * Top level procedure and MOUSE thread for the GAME demo.
  6399.   */
  6400.  int main(ac, av)
  6401.  int ac;
  6402.  char *av[];
  6403.  {
  6404.      /*
  6405.       * Parse the command line and perform some initialization.
  6406.       */
  6407.      if (ParseCmdLine(ac,av)) {
  6408.          printf("usage: %s [24|43] [F|M|S]\n",av[0]);
  6409.          DosExit(EXIT_THREAD,1);
  6410.      }
  6411.      if (InitGame())                /* Init game, exit if some problem */
  6412.          DosExit(EXIT_PROCESS,1);
  6413.  
  6414.      Defender();                 /* Run mouse loop (defend against the swarm)
  6415.  
  6416.      CleanUp();
  6417.  }
  6418.  
  6419.  /*
  6420.   * Defender()
  6421.   *
  6422.   * This is the main loop of the mouse control thread.
  6423.   *
  6424.   * The semaphore is used to prevent the other threads from time slicing
  6425.   * while this routine is examining and/or modifying the universe.  The
  6426.   * Semaphore is grabbed after the read of the Mouse queue so we don't tie
  6427.   * up the attackers while waiting for a mouse event.
  6428.   */
  6429.  void Defender()
  6430.  {
  6431.      USHORT ReadType = 1,        /* Wait for mouse events */
  6432.             alive,
  6433.             i;
  6434.      struct _MOUEVENTINFO  MouInfo;    /* mouse event packet structure */
  6435.  
  6436.      alive = CHASER;
  6437.  
  6438.      do {
  6439.          MouReadEventQue( &MouInfo, &ReadType, Mouse); /* read where mouse is
  6440.  
  6441.          DosSemRequest( &Semaphore, WAIT);
  6442.  
  6443.          if( MouInfo.fs & 1) {                      /* If the mouse has moved
  6444.              MOUSE.row = MouInfo.row;
  6445.              MOUSE.col = MouInfo.col;
  6446.          }
  6447.          if( MouInfo.fs & 4 ) {                       /* if left button presse
  6448.              for (i = 0; i < CHASER; i++ ) {
  6449.                  if( ( MOUSE.row == univ[i].row ) &&
  6450.                      ( MOUSE.col == univ[i].col ) &&  /* see if we hit one */
  6451.                      ( univ[i].state == ALIVE) ) {
  6452.                       univ[i].state = DEAD;
  6453.  
  6454.                       DosBeep(300,75);                     /* make a dying sou
  6455.                       DosBeep(600,75);
  6456.                       DosBeep(300,85);
  6457.  
  6458.                       alive--;                    /* Decrease number alive */
  6459.                       break;                    /* Can only kill one at a time
  6460.                  }
  6461.              }
  6462.          }
  6463.          if( MouInfo.fs & 16 )              /* If right button pressed... */
  6464.              break;                        /* End game, clean up */
  6465.  
  6466.          DosSemClear(&Semaphore);
  6467.      }
  6468.      while (GOAL.state == ALIVE && alive);    /* loop till all are dead */
  6469.  }
  6470.  
  6471.  /*
  6472.   * This thread manages the individual attackers.  It is spun off as
  6473.   * many times as needed for a game.
  6474.   *
  6475.   * The interaction of the mouse cursor and the chaser character is sort
  6476.   * of funny, hence the funny code, below.  The mouse cursor seems to
  6477.   * remember what was under it when it was written.  Hence we cannot erase
  6478.   * the chaser if the mouse is "sitting" on it.        If we do, then when the
  6479.   * mouse moves it will re-write the original object.  This shows up as
  6480.   * phantom chasers.
  6481.   */
  6482.  void far chasethread(ID)               /* code that controls each "chaser" */
  6483.  int ID;
  6484.  {
  6485.      short  row, col;               /* Our current position */
  6486.      short  deltaX, deltaY;     /* how far from the mouse are we? */
  6487.      short  danger;               /* flag to indicate not far enough! */
  6488.      short  m;                       /* general purpose indexes */
  6489.  
  6490.  
  6491.      /* Print out the initial chaser character */
  6492.  
  6493.      VioWrtCellStr( Chaser, 2, ME.row, ME.col, 0 );
  6494.  
  6495.      /*
  6496.       * Keep running as long as the goal and myself haven't been killed.
  6497.       */
  6498.      for (;;) {
  6499.  
  6500.          row = ME.row;                  /* Grab the current position */
  6501.          col = ME.col;
  6502.          /*
  6503.           * If mouse is sitting upon the chaser, do nothing.  Allow
  6504.           * the player some time to kill the chaser
  6505.           */
  6506.          if ((MOUSE.row == row) && (MOUSE.col == col)) {
  6507.              DosSleep( 1L );
  6508.              continue;
  6509.          }
  6510.          DosSemRequest(&Semaphore, WAIT);
  6511.          /*
  6512.           * If either the GOAL or Myself is dead, exit loop and clean up.
  6513.           * This wasn't tested in the for loop since we don't want to exit
  6514.           * if the MOUSE is sitting on the chaser.
  6515.           */
  6516.          if (ME.state != ALIVE || GOAL.state != ALIVE)
  6517.              break;
  6518.  
  6519.          deltaX = MOUSE.col - col;        /* calculate how far we are */
  6520.          deltaY = MOUSE.row - row;
  6521.  
  6522.          if (((deltaX < -DANGERZONE) || (DANGERZONE < deltaX)) ||
  6523.              ((deltaY < -DANGERZONE) || (DANGERZONE < deltaY))) {
  6524.  
  6525.              danger = 0;
  6526.  
  6527.              if(GOAL.row < row)                    /* Creep towards the GOAL *
  6528.                  row--;
  6529.              else if (GOAL.row > row)
  6530.                  row++;
  6531.              if(GOAL.col < col)
  6532.                  col--;
  6533.              else if(GOAL.col > col)
  6534.                  col++;
  6535.          }
  6536.          else {
  6537.              danger = 1;                     /* Run away from the mouse */
  6538.  
  6539.              if ((MOUSE.row > row) && (row > 0))
  6540.                  row--;
  6541.              else if ((MOUSE.row < row) && (row < ScreenHeight))
  6542.                  row++;
  6543.              if ((MOUSE.col > col) && (col < ScreenWidth))
  6544.                  col--;
  6545.              else if ((MOUSE.col < col) && (col > 0))
  6546.                  col++;
  6547.          }
  6548.          /*
  6549.           * A quick and Dirty hack to prevent chasers from merging
  6550.           */
  6551.          for (m = 0; m < CHASER; m++ ) {
  6552.              if (univ[m].state == ALIVE &&
  6553.                  univ[m].row == row &&
  6554.                  univ[m].col == col &&
  6555.                  m != ID) {
  6556.                 row += 1;
  6557.                 col += 3;
  6558.              }
  6559.          }
  6560.          /*
  6561.           * Zap the old chaser and print the new.  Release the semaphore
  6562.           * after this, there can be no undesirable interactions now.
  6563.           */
  6564.          VioWrtCellStr( Blank, 2, ME.row, ME.col, 0 );
  6565.          VioWrtCellStr( Chaser, 2, row, col, 0 );
  6566.  
  6567.          DosSemClear(&Semaphore);
  6568.          /*
  6569.           * Update the current location
  6570.           */
  6571.          ME.row = row;
  6572.          ME.col = col;
  6573.          /*
  6574.           * See if we have reached the GOAL, if so eat it and exit
  6575.           */
  6576.          if ((row == GOAL.row) && (col == GOAL.col)) {
  6577.              VioWrtCellStr( Blank, 2, row, col, 0 );
  6578.              DosBeep(600,175);
  6579.              DosBeep(1200,175);            /* if we reach the prize, let out a
  6580.              DosBeep(600,185);            /* paint the screen red and end the
  6581.              DosBeep(1200,175);
  6582.              VioScrollUp( 0, 0, -1, -1, -1, Blood, 0 );
  6583.              GOAL.state = DEAD;
  6584.          }
  6585.          /*
  6586.           * Sleep an amount of time that varies depending
  6587.           * upon the danger level
  6588.           */
  6589.          if( danger )
  6590.              DosSleep(Shortnap);
  6591.          else
  6592.              DosSleep(Longnap);
  6593.  
  6594.      }
  6595.      /*
  6596.       * chaser is now dead or the game is over.
  6597.       * Erase its body and terminate the thread.  Release the semaphore.
  6598.       */
  6599.      DosSemClear(&Semaphore);
  6600.  
  6601.      if (GOAL.state == ALIVE) {
  6602.          VioWrtCellStr(Blank, 2, ME.row, ME.col, 0 );
  6603.      }
  6604.      DosExit( EXIT_THREAD ,0);
  6605.  }
  6606.  
  6607.  /*
  6608.   * InitGame()
  6609.   *
  6610.   * Initialize the GOAL, MOUSE and the CHASERS, launch each chase thread.
  6611.   *
  6612.   * Returns an error if any internal processing errors
  6613.   */
  6614.  int InitGame()
  6615.  {
  6616.      struct _PTRLOC InitMouPos;
  6617.      void far chasethread();                /* code to control chasers */
  6618.      PBYTE Tstack;                        /* stack for new threads */
  6619.      unsigned chaseID;
  6620.      int i, rc;
  6621.      /*
  6622.       * Clear the screen.
  6623.       */
  6624.      VioScrollUp( 0, 0, -1, -1, -1, Blank, 0 );
  6625.      /*
  6626.       * Draw the prize
  6627.       */
  6628.      GOAL.row = ScreenHeight/2;
  6629.      GOAL.col = ScreenWidth /2;
  6630.      GOAL.state = ALIVE;
  6631.      VioWrtCellStr(Prize, 2, GOAL.row, GOAL.col, 0 );
  6632.      /*
  6633.       * Open the mouse pointer device and set it's location.
  6634.       */
  6635.      MouOpen( 0L, &Mouse );
  6636.      InitMouPos.row = GOAL.row;
  6637.      InitMouPos.col = GOAL.col;
  6638.      MouSetPtrPos( &InitMouPos, Mouse);
  6639.      MouDrawPtr(Mouse);
  6640.      /*
  6641.       * A simple minded initialization for the start of each chaser.
  6642.       * Some sort of random placement (based upon system time?) would
  6643.       * be nice.
  6644.       */
  6645.      univ[0].row = 0;  univ[0].col = 0;
  6646.      univ[1].row = 0;  univ[1].col = 25;
  6647.      univ[2].row = 0;  univ[2].col = 55;
  6648.      univ[3].row = 0;  univ[3].col = 79;
  6649.      univ[4].row = ScreenHeight;  univ[4].col = 0;
  6650.      univ[5].row = ScreenHeight;  univ[5].col = 25;
  6651.      univ[6].row = ScreenHeight;  univ[6].col = 55;
  6652.      univ[7].row = ScreenHeight;  univ[7].col = 79;
  6653.      /*
  6654.       * Grab the semaphore to prevent chaser from running until we are done.
  6655.       */
  6656.      DosSemRequest(&Semaphore, WAIT);
  6657.  
  6658.      for( i = 0; i < CHASER; i++ ) {                /* for each of our threads
  6659.          univ[i].state = ALIVE;                        /* Set each one alive *
  6660.          Tstack = (PBYTE)malloc(sizeof(int) * STACKSIZE);
  6661.          if (Tstack == NULL ) {                        /* Create a stack */
  6662.              printf( "thread %d stack malloc failed\n", i );
  6663.              return(1);
  6664.          }
  6665.          Tstack += sizeof(int)*STACKSIZE; /* set stack pointer to correct end
  6666.          *--Tstack = HIBYTE(i);
  6667.          *--Tstack = LOBYTE(i);                 /* Push the ID on as a paramet
  6668.  
  6669.          rc = DosCreateThread(chasethread, &chaseID, Tstack);
  6670.          if(rc) {
  6671.              printf( "create of thread %d failed, error: %d\n", i, rc );
  6672.              return (1);
  6673.          }
  6674.      }
  6675.      DosSemClear(&Semaphore);
  6676.  
  6677.      return (0);
  6678.  }
  6679.  
  6680.  /*
  6681.   * CleanUp()
  6682.   *
  6683.   * Routine to reset the Video modes back to where they were.
  6684.   * (As best as possible).
  6685.   */
  6686.  void CleanUp()
  6687.  {
  6688.      char blank[2];
  6689.  
  6690.      DosSleep(1L);             /* Yield the machine so attacker can clean up *
  6691.      VioSetMode( &OldVioMode, 0);
  6692.  /*
  6693.      blank[0] = ' ';
  6694.      blank[1] = OldVioMode.color;
  6695.      VioScrollUp( 0, 0, -1, -1, -1, blank, 0 );
  6696.  */
  6697.      VioSetCurType( &OldCur, 0);
  6698.      DosExit(EXIT_PROCESS,0);              /* Exit and terminate all threads.
  6699.  }
  6700.  
  6701.  /*
  6702.   * ParseCmdLine(ac, av)
  6703.   *
  6704.   * Parses the command line arguments and sets up the game accordingly
  6705.   *
  6706.   */
  6707.  int ParseCmdLine(ac,av)
  6708.  int ac;
  6709.  char **av;
  6710.  {
  6711.      struct _VIOMODEINFO modedata;
  6712.      int    VioMode;
  6713.  
  6714.      Longnap = LONGNAP;
  6715.      Shortnap = SHORTNAP;
  6716.      ScreenWidth = SCREEN_WIDTH;
  6717.      ScreenHeight = SCREEN_HEIGHT;
  6718.      VioMode = 25;
  6719.  
  6720.      while(--ac) {
  6721.          av++;
  6722.          switch(**av) {
  6723.              case 'f':
  6724.              case 'F':
  6725.                  Longnap = LONGNAP / 2;
  6726.                  Shortnap= SHORTNAP/ 2;
  6727.                  break;
  6728.              case 'm':
  6729.              case 'M':
  6730.                  Longnap = LONGNAP;
  6731.                  Shortnap= SHORTNAP;
  6732.                  break;
  6733.              case 's':
  6734.              case 'S':
  6735.                  Longnap = LONGNAP * 2;
  6736.                  Shortnap= SHORTNAP* 2;
  6737.                  break;
  6738.              case '4':            /* Assume 43 line mode was wanted */
  6739.                  ScreenHeight = 42;
  6740.                  ScreenWidth  = 79;
  6741.                  VioMode = 43;
  6742.                  break;
  6743.              case '2':
  6744.                  ScreenHeight = 24;
  6745.                  ScreenWidth  = 79;
  6746.                  VioMode = 25;
  6747.                  break;
  6748.              default:
  6749.                  return(1);
  6750.          }
  6751.      }
  6752.  
  6753.      VioGetCurType(&OldCur, 0);                /* Save old cursor */
  6754.  
  6755.      modedata.cb = sizeof(modedata); /* change mode as needed */
  6756.      VioGetMode( &modedata, 0);
  6757.      OldVioMode = modedata;
  6758.      modedata.row = VioMode;
  6759.      VioSetMode( &modedata, 0);
  6760.  
  6761.      NewCur.yStart = 0;
  6762.      NewCur.cEnd = 0;
  6763.      NewCur.cx = 1;
  6764.      NewCur.attr = -1;
  6765.  
  6766.      VioSetCurType( &NewCur, 0 );         /* make cursor go away */
  6767.  
  6768.      return (0);
  6769.  }
  6770.  
  6771.  
  6772.  CIRCLEQ.C
  6773.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\COMTALK\CIRCLEQ.C
  6774.  
  6775.  /*
  6776.      Circular Queue buffer implementation (which gets read by AVIO module)
  6777.      Created by Microsoft Corporation, 1989
  6778.  */
  6779.  #define INCL_DOSSEMAPHORES
  6780.  <os2.h>                /* Need USHORT for global.h */
  6781.  <string.h>                /* One strcpy call */
  6782.  #include "global.h"
  6783.  #include "circleq.h"
  6784.  
  6785.         TIMEOUT        1000L                /* A second */
  6786.  
  6787.  LineInfo aliRing[QUEUESIZE];        /* The Circular Queue...*/
  6788.  int  iHead, iTail;
  6789.  BOOL fFirst;                        /* Are we just starting? */
  6790.  LONG lSemMyQueue;                /* Queue lock */
  6791.  
  6792.  void LineCopy(Line, Line);
  6793.  void QueFill(void);
  6794.  
  6795.  #define QueLock()   DosSemRequest(&lSemMyQueue, -1L)
  6796.  #define QueUnlock() DosSemClear(&lSemMyQueue)
  6797.  
  6798.  #define Fix(n) (((n) >= 0) ? (n) : ((n) + QUEUESIZE))
  6799.  #define Circle(x)        ((x) % QUEUESIZE)
  6800.  #define Incr(x)         (x = Circle(x + 1))
  6801.  #define Decr(x)                (x = (x > 0) ? (x - 1) : (QUEUESIZE - 1))
  6802.  
  6803.  void QueFill(void) {
  6804.      int i, j;
  6805.  
  6806.      for (i = 0; i < 25; i++) {
  6807.          aliRing[i].cch = MAXLINELEN;
  6808.          for (j = 0; j < MAXLINELEN; j++)
  6809.              aliRing[i].szText[j] = (char) (((i * j) % 10) + '0');
  6810.      }
  6811.      iHead = 0; iTail = 24;
  6812.  }
  6813.  
  6814.  void QueInit(void) {
  6815.      int i;
  6816.  
  6817.      fFirst = TRUE;
  6818.      QueLock();
  6819.      iHead = 0; iTail = 0;
  6820.      for (i = 0; i < QUEUESIZE; i++) aliRing[i].cch = 0;
  6821.      QueUnlock();
  6822.  }
  6823.  
  6824.  void QueAdvance(int n) {
  6825.      QueLock();
  6826.      iHead = Circle(iHead + n);
  6827.      QueUnlock();
  6828.  }
  6829.  
  6830.  Line QueQuery(int LineNum) { return &aliRing[Circle(iHead + LineNum)]; }
  6831.  
  6832.  BOOL QueInsertLine(Line pli) {
  6833.  /*
  6834.      Return FALSE if we try to overwrite the head
  6835.  */
  6836.      QueLock();
  6837.      /*
  6838.          Initialize the queue
  6839.      */
  6840.      if (fFirst) fFirst = FALSE;
  6841.      /*
  6842.          Increment TAIL, act if queue full
  6843.          Overwrite if last entry was incomplete
  6844.      */
  6845.      else if (aliRing[iTail].fComplete && (Incr(iTail) == iHead)) {
  6846.          /*
  6847.              We are overflowing...
  6848.          */
  6849.          Decr(iTail);
  6850.          QueUnlock();
  6851.          return FALSE;
  6852.      }
  6853.      /*
  6854.          Insert the element
  6855.      */
  6856.      LineCopy(pli, &aliRing[iTail]);
  6857.      QueUnlock();
  6858.      return TRUE;
  6859.  }
  6860.  
  6861.  BOOL QueCompleteLine(void) { return aliRing[iTail].fComplete; }
  6862.  
  6863.  void LineCopy(Line pliSrc, Line pliDst) {
  6864.      int i;
  6865.  
  6866.      pliDst->fDrawn                = pliSrc->fDrawn;
  6867.      pliDst->fComplete                = pliSrc->fComplete;
  6868.      pliDst->cch                        = pliSrc->cch;
  6869.      for (i = 0; i < (int) pliSrc->cch; i++) pliDst->szText[i] = pliSrc->szTex
  6870.  }
  6871.  
  6872.  int QueUpdateHead(int nRows, BOOL bPage, BOOL bPaging) {
  6873.      int i, nLines;
  6874.  
  6875.      nLines = Fix(Circle(iTail - iHead));
  6876.      nLines = (nLines >= nRows) ? (nLines - nRows + 1) : 0;
  6877.      if ((nLines = Min(nLines, nRows)) > 0) {
  6878.          if (bPage) {
  6879.              if (nLines < nRows) {
  6880.                  QueLock();
  6881.                  for (i = nLines; i < nRows; i++)
  6882.                      aliRing[Circle(iHead + nRows + i)].cch = 0;
  6883.                  QueUnlock();
  6884.              }
  6885.              nLines = nRows;
  6886.          }
  6887.          else if (bPaging) nLines = 0;
  6888.          QueLock();
  6889.          iHead = Circle(iHead + nLines);
  6890.          QueUnlock();
  6891.      }
  6892.      return nLines;
  6893.  }
  6894.  
  6895.  Line QueLastLine(void) {
  6896.      QueLock();
  6897.      aliRing[iTail].szText[aliRing[iTail].cch] = '\0';
  6898.      QueUnlock();
  6899.      return &aliRing[iTail];
  6900.  }
  6901.  
  6902.  int QuePageUp(int nRows) {
  6903.      int i, nLines;
  6904.  
  6905.      QueLock();
  6906.      nLines = Min((QUEUESIZE - 1) - Fix(Circle(iTail - iHead)), nRows);
  6907.      if (nLines) {
  6908.          iHead = Fix(Circle(iHead - nLines));
  6909.          for (i = 0; i < nLines; i++)
  6910.              aliRing[Circle(iHead + nRows + i)].fDrawn = FALSE;
  6911.      }
  6912.      QueUnlock();
  6913.      return nLines;
  6914.  }
  6915.  
  6916.  
  6917.  CLIPFILE.C
  6918.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CLIPVIEW\CLIPFILE.C
  6919.  
  6920.  /*
  6921.   * CLIPFILE.C -- File handling for ClipView
  6922.   * Created by Microsoft Corporation, 1989
  6923.   *
  6924.   * This file contains one routine:  SaveClipboard(), which uses
  6925.   * the OPENDLG library to put up a File...Save... dialog box.
  6926.   *
  6927.   * After getting a file name, it tries to save the current rendered format.
  6928.   */
  6929.  #define INCL_BITMAPFILEFORMAT
  6930.  #define        INCL_DOSFILEMGR
  6931.  #define INCL_DOSMEMMGR
  6932.  #define INCL_GPIBITMAPS
  6933.  #define        INCL_GPIMETAFILES
  6934.  #define        INCL_WINCLIPBOARD
  6935.  #define        INCL_WINERRORS
  6936.  #include <os2.h>
  6937.  #include <opendlg.h>
  6938.  #include <string.h>
  6939.  #include "clipview.h"
  6940.  /*
  6941.   * Globals
  6942.   */
  6943.  extern HAB        vhab;                        /* Anchor block
  6944.  extern HWND        vhwndClient;                /* Main client area        */
  6945.  /*
  6946.      Macros
  6947.  */
  6948.  #define CHK(f) fSuccess = fSuccess && (f)
  6949.  #define LOADSTRING(id, sz) WinLoadString(vhab, (HMODULE) NULL, id, MAXLEN, sz
  6950.  /*
  6951.      Private function prototypes
  6952.  */
  6953.  BOOL SaveText(HFILE hf, PSZ pszText);
  6954.  
  6955.  BOOL SaveClipboard(HWND hwnd, USHORT usFormat) {
  6956.  /*
  6957.      Save the clipboard contents in several formats.
  6958.      The "Save BITMAP" code is similar to that in the LINEFRAC sample.
  6959.  */
  6960.      BOOL                fSuccess = TRUE;     /* Did we succeed in saving? */
  6961.      ULONG                hItem;                     /* Handle from QueryClipb
  6962.      /*
  6963.          Variables needed for File...Save... dialog.
  6964.      */
  6965.      DLF                 dlf;                     /* Dialog file */
  6966.      HFILE                hf;                     /* Handle to output file */
  6967.      UCHAR                szExt[8];             /* Default extension */
  6968.      UCHAR                szInst[MAXLEN];      /* Instructions */
  6969.      UCHAR                szMessage[MAXLEN];   /* Various messages */
  6970.      UCHAR                szTitle[MAXTITLELEN];/* Application title */
  6971.      /*
  6972.          Variables needed for saving Metafiles
  6973.      */
  6974.      HMF                 hmfCopy;             /* Clipboard metafile copy */
  6975.      /*
  6976.          Variables needed for saving BITMAPs
  6977.      */
  6978.      BITMAPINFOHEADER        bmp;                /* Header to be queried */
  6979.      HDC                 hdcMemory;        /* Memory DC for the BITMAP */
  6980.      HPS                 hpsMemory;        /* ...and it's associated PS */
  6981.      PBITMAPFILEHEADER        pbfh;                /* bmp + color table */
  6982.      POINTL                ptlOrigin;        /* Bitmap origin */
  6983.      SEL                 selBuffer;        /* Selector to actual BITMAP */
  6984.      SEL                 selHeader;        /* Selector for the BMP header */
  6985.      SIZEL                sizl;                /* Used in PS creation */
  6986.      ULONG                cbBuffer;        /* No. of bytes in buffer */
  6987.      USHORT                cbExtra;        /* No. of bytes in "final" segment
  6988.      USHORT                cbHeader;        /* No. of bytes in header */
  6989.      USHORT                cbWrite1;        /* No. of bytes to be written... *
  6990.      USHORT                cbWrite2;        /* ...in the two-part sel writes *
  6991.      USHORT                cbWritten;        /* No. of bytes actually written
  6992.      USHORT                cSegs;                /* No. of segments to write *
  6993.      USHORT                i;                /* Which segment is being written
  6994.      USHORT                usHugeShift;
  6995.      /*
  6996.          Open the clipboard
  6997.      */
  6998.      if (!WinOpenClipbrd(vhab))
  6999.          return FALSE;
  7000.      /*
  7001.          Get the clipboard data
  7002.      */
  7003.      if (hItem = WinQueryClipbrdData(vhab, usFormat)) {
  7004.          /*
  7005.              Put up the Save... file dialog with the appropriate extensions
  7006.          */
  7007.          switch (usFormat) {
  7008.              case CF_TEXT:
  7009.              case CF_DSPTEXT:         strcpy(szExt, "\\*.TXT");  break;
  7010.  
  7011.              case CF_BITMAP:
  7012.              case CF_DSPBITMAP:         strcpy(szExt, "\\*.BMP");  break;
  7013.  
  7014.              case CF_METAFILE:
  7015.              case CF_DSPMETAFILE: strcpy(szExt, "\\*.MET");  break;
  7016.  
  7017.              default:                 strcpy(szExt, "\\*.*");    break;
  7018.          }
  7019.          /*
  7020.              Put the string "Saving Format:  <format>" in the Save dialog box
  7021.          */
  7022.          GetFormatName(usFormat, szMessage);
  7023.          LOADSTRING(IDS_SAVETITLE, szTitle);
  7024.          strcat(szTitle, szMessage);
  7025.  
  7026.          LOADSTRING(IDS_APPNAME, szMessage);
  7027.          LOADSTRING(IDS_INST, szInst);
  7028.  
  7029.          SetupDLF(&dlf, DLG_SAVEDLG, &hf,
  7030.                   (PSZ) szExt, (PSZ) szMessage, (PSZ) szTitle, (PSZ) szInst);
  7031.  
  7032.          dlf.szFileName[0] = dlf.szOpenFile[0] = '\0';
  7033.          /*
  7034.              Put up a Save file dialog, and respond appropriately to
  7035.              the return status.
  7036.          */
  7037.          switch (DlgFile(hwnd, &dlf)) {
  7038.              case TDF_ERRMEM:
  7039.              case TDF_INVALID:
  7040.              case TDF_NOSAVE:
  7041.                  fSuccess = FALSE;
  7042.  
  7043.                  /* fall through... */
  7044.              default:
  7045.                  break;
  7046.          }
  7047.  
  7048.          if (fSuccess) {
  7049.            switch (usFormat) {
  7050.  
  7051.              case CF_TEXT:
  7052.              case CF_DSPTEXT:
  7053.                  CHK(SaveText(hf, MAKEP((SEL) hItem, 0)));
  7054.                  DosClose(hf);
  7055.                  break;
  7056.  
  7057.              case CF_BITMAP:
  7058.              case CF_DSPBITMAP:
  7059.                  /*
  7060.                      Initialize the Memory DC and its PS
  7061.                  */
  7062.                  sizl.cx = sizl.cy = 0L;
  7063.                  hdcMemory = DevOpenDC(vhab, OD_MEMORY, "*", 0L, NULL, NULL);
  7064.                  hpsMemory = GpiCreatePS(vhab, hdcMemory, &sizl,
  7065.                                    GPIA_ASSOC | GPIT_MICRO | PU_PELS);
  7066.                  /*
  7067.                      Draw the BITMAP into the Memory DC
  7068.                  */
  7069.                  CHK(GpiSetBitmap(hpsMemory, (HBITMAP) hItem) != HBM_ERROR);
  7070.                  ptlOrigin.x = ptlOrigin.y = 0L;
  7071.                  CHK(WinDrawBitmap(hpsMemory, (HBITMAP) hItem, NULL,
  7072.                             &ptlOrigin, CLR_BLACK, CLR_BACKGROUND, DBM_NORMAL)
  7073.                  /*
  7074.                      Get information about the BITMAP
  7075.                  */
  7076.                  CHK(GpiQueryBitmapParameters((HBITMAP) hItem, &bmp) == GPI_OK
  7077.                  /*
  7078.                      Compute the size of the buffer, and allocate
  7079.                      Make sure that > 64K BITMAPs are handled
  7080.                      (this code is from LFFILE.C)
  7081.                  */
  7082.                  cbBuffer = ( ((((ULONG)bmp.cBitCount*(ULONG) bmp.cx)+31L)/32L
  7083.                                  * 4L * (ULONG) bmp.cy * (ULONG) bmp.cPlanes )
  7084.                  cSegs   = (USHORT) (cbBuffer >> 16);
  7085.                  cbExtra = (USHORT) (cbBuffer & 0xFFFFL);
  7086.                  CHK(!DosAllocHuge(cSegs, cbExtra, &selBuffer, 0, 0));
  7087.                  CHK(!DosGetHugeShift(&usHugeShift));
  7088.                  /*
  7089.                      Compute the size of the BITMAPFILEHEADER + color table...
  7090.                      ...then allocate it.
  7091.                  */
  7092.                  cbHeader = (USHORT) (sizeof(BITMAPFILEHEADER)
  7093.                                  + (sizeof(RGB) << bmp.cBitCount));
  7094.                  CHK(!DosAllocSeg(cbHeader, &selHeader, SEG_NONSHARED));
  7095.                  pbfh = MAKEP(selHeader, 0);
  7096.                  /*
  7097.                      Copy the BITMAP information from the BITMAPINFOHEADER
  7098.                  */
  7099.                  pbfh->bmp.cbFix     = 12;
  7100.                  pbfh->bmp.cx            = bmp.cx;
  7101.                  pbfh->bmp.cy            = bmp.cy;
  7102.                  pbfh->bmp.cPlanes   = bmp.cPlanes;
  7103.                  pbfh->bmp.cBitCount = bmp.cBitCount;
  7104.                  /*
  7105.                      Get the actual BITMAP bits
  7106.                  */
  7107.                  CHK(GpiQueryBitmapBits(hpsMemory, 0L, (LONG) bmp.cy,
  7108.                         MAKEP(selBuffer, 0), (PBITMAPINFO) &(pbfh->bmp))
  7109.                      != GPI_ALTERROR);
  7110.                  /*
  7111.                      Set up the file header
  7112.                  */
  7113.                  pbfh->usType            = BFT_BMAP;
  7114.                  pbfh->cbSize            = cbHeader + cbBuffer;
  7115.                  pbfh->xHotspot            = bmp.cx / 2;        /* Anywhere wi
  7116.                  pbfh->yHotspot            = bmp.cy / 2;
  7117.                  pbfh->offBits            = cbHeader;
  7118.              /*
  7119.                  Blast the BITMAP to a file...
  7120.              */
  7121.                  /*
  7122.                      ...first, the header...
  7123.                  */
  7124.                  CHK(!DosWrite(hf, pbfh, cbHeader, &cbWritten));
  7125.                  /*
  7126.                      ...then, the possibly large BITMAP itself
  7127.                  */
  7128.                  for (i = 0; i <= cSegs; ++i) {
  7129.                      if (i < cSegs) {
  7130.                      /*
  7131.                          If we a 64K segment, write it in two
  7132.                          parts.         This must be done because
  7133.                          DosWrite() can only write 64K - 1
  7134.                          characters at once.
  7135.                      */
  7136.                          cbWrite1 = cbWrite2 = 0x8000;
  7137.                      } else {
  7138.                      /*
  7139.                          The last segment is always small enough
  7140.                          to write entirely.
  7141.                      */
  7142.                          cbWrite1 = cbExtra; cbWrite2 = 0;
  7143.                      }
  7144.  
  7145.                      if (cbWrite1) {
  7146.                          CHK(!DosWrite(hf,
  7147.                                  MAKEP((selBuffer + (i << usHugeShift)), 0),
  7148.                                  cbWrite1, &cbWritten));
  7149.                          if (cbWrite2) {
  7150.                              CHK(!DosWrite(hf,
  7151.                                  MAKEP((selBuffer + (i<<usHugeShift)),cbWrite1
  7152.                                  cbWrite2, &cbWritten));
  7153.                          }
  7154.                      }
  7155.                  }
  7156.                  /*
  7157.                      Clean up
  7158.  
  7159.                      Error codes are not checked here because the file has
  7160.                      already been saved.
  7161.                  */
  7162.                  DosClose(hf);
  7163.                  GpiSetBitmap(hpsMemory, NULL);
  7164.                  GpiDestroyPS(hpsMemory);
  7165.                  DevCloseDC(hdcMemory);
  7166.                  break;
  7167.  
  7168.              case CF_METAFILE:
  7169.              case CF_DSPMETAFILE:
  7170.                  /*
  7171.                      Save metafile
  7172.  
  7173.                      We close and delete the file, because GpiSaveMetaFile()
  7174.                      only allows the user to create a new file.
  7175.  
  7176.                      We copy the metafile because GpiSaveMetafile()
  7177.                      removes the data from the application's memory.
  7178.                  */
  7179.                  DosClose(hf);
  7180.                  CHK(!DosDelete(dlf.szFileName, 0L));
  7181.                  CHK((hmfCopy = GpiCopyMetaFile((HMF) hItem)) != GPI_ERROR);
  7182.                  CHK(GpiSaveMetaFile(hmfCopy, dlf.szFileName) != GPI_ERROR);
  7183.                  break;
  7184.  
  7185.              default:
  7186.                  /*
  7187.                      It may be reasonable to add support for other formats
  7188.                      here, by saving a bitmap of the current window contents.
  7189.  
  7190.                      But for now, close the file and return an error message.
  7191.                  */
  7192.                  DosClose(hf);
  7193.                  fSuccess = FALSE;
  7194.                  break;
  7195.            }
  7196.          }
  7197.      } else
  7198.          fSuccess = FALSE;        /* Couldn't query the clipboard format! */
  7199.      /*
  7200.          Clean up
  7201.      */
  7202.      WinCloseClipbrd(vhab);
  7203.      return fSuccess;
  7204.  }
  7205.  
  7206.  BOOL SaveText(HFILE hf, PSZ pszText) {
  7207.  /*
  7208.      Save text format
  7209.  
  7210.      Count the number of characters, then write them.
  7211.  */
  7212.      PSZ     pszCounter;     /* Temporary to count chars in sel */
  7213.      ULONG   ulcch = 0;            /* The number of characters */
  7214.      USHORT  cbWritten;            /* No. of bytes actually written */
  7215.  
  7216.      pszCounter = pszText;
  7217.      while (*pszCounter++) ulcch++;
  7218.  
  7219.      return(!DosWrite(hf, pszText, (USHORT) ulcch, &cbWritten));
  7220.  }
  7221.  
  7222.  
  7223.  CLIPVIEW.C
  7224.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CLIPVIEW\CLIPVIEW.C
  7225.  
  7226.  /*
  7227.   * CLIPVIEW.C -- Clipboard Viewing application
  7228.   * Created by Microsoft Corporation, 1989
  7229.   *
  7230.   * This program registers itself as the clipboard viewer, if no clipboard
  7231.   * viewer exists.  Then, it intercepts WM_DRAWCLIPBOARD messages.
  7232.   *
  7233.   * This file contains the routines which handle the client/frame windows,
  7234.   * the dialog routines, and the clipboard rendering code.
  7235.   */
  7236.  #define        INCL_GPIBITMAPS
  7237.  #define        INCL_GPIMETAFILES
  7238.  #define INCL_WINATOM
  7239.  #define        INCL_WINCLIPBOARD
  7240.  #define        INCL_WINFRAMEMGR
  7241.  #define        INCL_WINLISTBOXES
  7242.  #define        INCL_WINMENUS
  7243.  #define        INCL_WINMLE
  7244.  #define        INCL_WINSCROLLBARS
  7245.  #define        INCL_WINSYS
  7246.  #define        INCL_WINWINDOWMGR
  7247.  #include <os2.h>
  7248.  #include <string.h>
  7249.  #include "clipview.h"
  7250.  /*
  7251.   * Globals
  7252.   */
  7253.  BITMAPINFOHEADER vbmp;                        // Dimensions of current BITMAP
  7254.  BOOL        vfUpdate        = FALSE;        // Are we updating the clipboard?
  7255.  BOOL        vfViewBitmap        = FALSE;        // Are we currently viewing a
  7256.  HAB        vhab;                                // Anchor block
  7257.  HDC        vhdcMemory;                        // A memory DC for BitBlt-ing i
  7258.  HDC        vhdcWindow        = NULL;         // Client window DC
  7259.  HMQ        vhmqClip;                        // Message queue
  7260.  HPS        vhpsMemory;                        // A PS associated with vhdcMem
  7261.  HWND        vhwndClient;                        // Main client area
  7262.  HWND        vhwndClipFrame = NULL;                // Main frame window
  7263.  HWND        vhwndHSB        = NULL;         // Horizontal scroll bar
  7264.  HWND        vhwndMLE        = NULL;         // Handle to the MLE
  7265.  HWND        vhwndTitlebar        = NULL;         // Title-bar handle
  7266.  HWND        vhwndVSB        = NULL;         // Vertical scroll bar
  7267.  SHORT        vcMaxHSB;                        // Maximum scroll range for HSB
  7268.  SHORT        vcMaxVSB;                        // ...and for the VSB
  7269.  SHORT        vcUpdate        = -1;                // Counter for scroll bar u
  7270.  USHORT        vausFormats[MAXFORMATS];        // All available formats
  7271.  USHORT        vcFmts;                         // How many formats?
  7272.  USHORT        vusFormat;                        // What is the current format
  7273.  USHORT        vfsFmtInfo;                        // Clipboard Format Informat
  7274.  /*
  7275.      Macros
  7276.  */
  7277.  #define LOADSTRING(id, sz) WinLoadString(vhab, (HMODULE) NULL, id, MAXLEN, sz
  7278.  #define MESSAGE(sz) WinMessageBox(HWND_DESKTOP, vhwndClient, sz, NULL, 0, \
  7279.                          MB_OK | MB_ICONASTERISK | MB_SYSTEMMODAL);
  7280.  /*
  7281.   * Main routine...initializes window and message queue
  7282.   */
  7283.  int cdecl main( ) {
  7284.      QMSG    qmsg;                    /* Message queue */
  7285.      ULONG   ctldata;                    /* FCF_ flags */
  7286.      BOOL    fViewer;                    /* Does a viewer already exist? */
  7287.      UCHAR   szAlready[MAXLEN];            /* Already extant... message */
  7288.      UCHAR   szClassName[MAXLEN];    /* New class name */
  7289.      /*
  7290.          Start up our PM application
  7291.      */
  7292.      vhab = WinInitialize(0);
  7293.      vhmqClip = WinCreateMsgQueue(vhab, 0);
  7294.      /*
  7295.          We create the client window first to try to avoid
  7296.          synchronization problems.
  7297.      */
  7298.      LOADSTRING(IDS_CLIPCLASS, szClassName);
  7299.      if (!WinRegisterClass( vhab, (PCH)szClassName, (PFNWP)ClipWndProc,
  7300.                  CS_SIZEREDRAW, 0))
  7301.          return( 0 );
  7302.      /*
  7303.          Create the window (hidden)
  7304.      */
  7305.      ctldata = (FCF_STANDARD | FCF_HORZSCROLL | FCF_VERTSCROLL)
  7306.                              & ~(FCF_ACCELTABLE);
  7307.  
  7308.      vhwndClipFrame = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE, &ctldata,
  7309.                                           szClassName, "",
  7310.                                           WS_VISIBLE, (HMODULE) NULL, ID_RESOU
  7311.                                           (PHWND) &vhwndClient );
  7312.      /*
  7313.          If there is no other clipboard viewer...
  7314.      */
  7315.      if (fViewer = !WinQueryClipbrdViewer(vhab, FALSE)) {
  7316.          /*
  7317.              ...we'll be the viewer.  Show the clipboard window.
  7318.          */
  7319.          WinSetClipbrdViewer(vhab, vhwndClient);
  7320.          /*
  7321.              Poll messages from event queue
  7322.          */
  7323.          while( WinGetMsg( vhab, (PQMSG)&qmsg, (HWND)NULL, 0, 0 ) )
  7324.              WinDispatchMsg( vhab, (PQMSG)&qmsg );
  7325.          /*
  7326.              Stop being the clipboard viewer.
  7327.          */
  7328.          if (vhwndMLE)
  7329.              WinDestroyWindow(vhwndMLE);
  7330.          WinSetClipbrdViewer(vhab, NULL);
  7331.      } else {
  7332.          /*
  7333.              ...otherwise, notify the user, then terminate.
  7334.          */
  7335.          LOADSTRING(IDS_ALREADY, szAlready);
  7336.          MESSAGE(szAlready);
  7337.      }
  7338.      /*
  7339.          Clean up
  7340.      */
  7341.      WinDestroyWindow( vhwndClipFrame );
  7342.      WinDestroyMsgQueue( vhmqClip );
  7343.      WinTerminate( vhab );
  7344.  
  7345.      return !fViewer;
  7346.  }
  7347.  
  7348.  MRESULT CALLBACK ClipWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
  7349.  /*
  7350.  
  7351.   * This routine processes WM_COMMAND, WM_CREATE, WM_DRAWCLIPBOARD, WM_PAINT.
  7352.   * Everything else is passed to the Default Window Procedure.
  7353.   */
  7354.      HPS                hpsWindow;
  7355.      RECTL        rcl;
  7356.      SWP         swp;
  7357.      SIZEL        sizl;
  7358.      UCHAR        szMessage[MAXLEN];
  7359.  
  7360.      switch (msg) {
  7361.  
  7362.          case WM_CREATE:
  7363.              /*
  7364.                  Create a memory DC/PS to BitBlt BITMAPs around.
  7365.              */
  7366.              sizl.cx = sizl.cy = 0L;
  7367.              vhdcMemory = DevOpenDC(vhab, OD_MEMORY, "*", 0L, NULL, NULL);
  7368.              vhpsMemory = GpiCreatePS(vhab, vhdcMemory, &sizl,
  7369.                  GPIA_ASSOC | GPIF_DEFAULT | GPIT_MICRO | PU_PELS);
  7370.              break;
  7371.  
  7372.          case WM_COMMAND:
  7373.              switch (COMMANDMSG(&msg)->cmd) {
  7374.                  /*
  7375.                      About... dialog box
  7376.                  */
  7377.                  case IDM_ABOUT:
  7378.                      WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc,
  7379.                                (HMODULE) NULL, IDD_ABOUT, NULL);
  7380.                      return 0;
  7381.                  /*
  7382.                      Render... dialog box
  7383.                  */
  7384.                  case IDM_RENDER:
  7385.                      WinDlgBox(HWND_DESKTOP, hwnd, RenderDlgProc,
  7386.                                (HMODULE) NULL, IDD_RENDER, NULL);
  7387.                      return 0;
  7388.                  /*
  7389.                      Save... dialog box
  7390.                  */
  7391.                  case IDM_SAVE:
  7392.                      if (!SaveClipboard(hwnd, vusFormat)) {
  7393.                          LOADSTRING(IDS_NOTSAVED, szMessage);
  7394.                          MESSAGE(szMessage);
  7395.                      }
  7396.                      return 0;
  7397.  
  7398.                  default: break;
  7399.              }
  7400.              break;
  7401.  
  7402.          case WM_ERASEBACKGROUND:
  7403.              return (MRESULT) TRUE;
  7404.              break;
  7405.  
  7406.          case WM_PAINT:
  7407.              /* Open the presentation space */
  7408.              hpsWindow = WinBeginPaint(hwnd, NULL, &rcl);
  7409.  
  7410.              /* Fill in the background */
  7411.              WinFillRect(hpsWindow, &rcl, CLR_BACKGROUND);
  7412.  
  7413.              /* Paint in the clipboard */
  7414.              UpdateScreen(hwnd, vusFormat);
  7415.  
  7416.              /* Finish painting */
  7417.              WinEndPaint(hpsWindow);
  7418.              break;
  7419.  
  7420.          case WM_DRAWCLIPBOARD:
  7421.              /* Update the clipboard contents */
  7422.              GetAllFormats();
  7423.              vfUpdate = TRUE;
  7424.              WinPostMsg(hwnd, WM_PAINT, 0L, 0L);
  7425.              break;
  7426.  
  7427.          case WM_HSCROLL:
  7428.              if (vfViewBitmap) {
  7429.                  /*
  7430.                      Handle the appropriate scrolling messages
  7431.                  */
  7432.                  DoScrolling(hwnd, TRUE, HIUSHORT(mp2));
  7433.              } else
  7434.                  /*
  7435.                      If an ownerdraw format, let the owner handle it.
  7436.                  */
  7437.                  SendOwnerMsg(WM_HSCROLLCLIPBOARD, (MPARAM) hwnd, mp2);
  7438.              break;
  7439.  
  7440.          case WM_VSCROLL:
  7441.              if (vfViewBitmap) {
  7442.                  /*
  7443.                      Handle the appropriate scrolling messages
  7444.                  */
  7445.                  DoScrolling(hwnd, FALSE, HIUSHORT(mp2));
  7446.              } else
  7447.                  /*
  7448.                      If an ownerdraw format, let the owner handle it.
  7449.                  */
  7450.                  SendOwnerMsg(WM_VSCROLLCLIPBOARD, (MPARAM) hwnd, mp2);
  7451.              break;
  7452.  
  7453.          case WM_SIZE:
  7454.              /*
  7455.                  If the MLE is processing a text selector,
  7456.                  tell it to resize itself.  If we have
  7457.                  owner-draw data, tell the clipboard owner.
  7458.                  If we have a BITMAP, readjust the scroll
  7459.                  bar ranges.
  7460.              */
  7461.              if (vhwndMLE) {
  7462.                  WinQueryWindowPos(vhwndMLE, &swp);
  7463.                  swp.cx = SHORT1FROMMP(mp2);
  7464.                  swp.cy = SHORT2FROMMP(mp2);
  7465.                  WinSetMultWindowPos(vhab, &swp, 1);
  7466.              } else if (vfViewBitmap) {
  7467.                  WinQueryWindowPos(hwnd, &swp);
  7468.                  if ((vcMaxHSB = vbmp.cx - swp.cx) < 0)
  7469.                      vcMaxHSB = 0;
  7470.                  if ((vcMaxVSB = vbmp.cy - swp.cy) < 0)
  7471.                      vcMaxVSB = 0;
  7472.                  WinSendMsg(vhwndHSB, SBM_SETSCROLLBAR,
  7473.                      0L, MPFROM2SHORT(0, vcMaxHSB));
  7474.                  WinSendMsg(vhwndVSB, SBM_SETSCROLLBAR,
  7475.                      MPFROMSHORT(vcMaxVSB),
  7476.                      MPFROM2SHORT(0, vcMaxVSB));
  7477.              } else {
  7478.                  rcl.xLeft = rcl.yBottom = 0L;
  7479.                  rcl.xLeft = (LONG) SHORT1FROMMP(mp2) - 1;
  7480.                  rcl.yTop  = (LONG) SHORT2FROMMP(mp2) - 1;
  7481.                  SendOwnerMsg(WM_SIZECLIPBOARD, (MPARAM) hwnd, &rcl);
  7482.              }
  7483.              break;
  7484.  
  7485.          default:
  7486.              return WinDefWindowProc(hwnd, msg, mp1, mp2);
  7487.              break;
  7488.      }
  7489.      return 0L;
  7490.  }
  7491.  
  7492.  MRESULT CALLBACK RenderDlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM m
  7493.  {
  7494.  /*
  7495.      Render... dialog procedure
  7496.  */
  7497.      HWND        hwndListbox;                /* Listbox of possible formats */
  7498.      UCHAR        szFmtName[MAXLEN];        /* Format name */
  7499.      UCHAR        szMessage[MAXLEN];
  7500.      USHORT        i;
  7501.      USHORT        usFormat;                /* Format to render */
  7502.      MRESULT        mrItem;                 /* Which listbox item selected? */
  7503.  
  7504.      switch(msg) {
  7505.  
  7506.          case WM_INITDLG:
  7507.              /*
  7508.                  Put all the possible formats into the listbox, and
  7509.                  select the first item by default.
  7510.              */
  7511.              hwndListbox = WinWindowFromID(hwndDlg, IDL_RENDER);
  7512.              WinSendMsg(hwndListbox, LM_DELETEALL, 0L, 0L);
  7513.              for (i = 0; i < vcFmts; i++) {
  7514.                  GetFormatName(vausFormats[i], szFmtName);
  7515.                  WinSendMsg(hwndListbox, LM_INSERTITEM,
  7516.                          MPFROMSHORT(LIT_END), MPFROMP((PVOID) szFmtName));
  7517.              }
  7518.              WinSendMsg(hwndListbox, LM_SELECTITEM, 0L, MPFROMSHORT(TRUE));
  7519.              break;
  7520.  
  7521.          case WM_CONTROL:
  7522.              /*
  7523.                  If the user makes a selection, quit!
  7524.              */
  7525.              if ((SHORT1FROMMP(mp1) == IDL_RENDER)
  7526.                  && (SHORT2FROMMP(mp1) == LN_ENTER))
  7527.                      WinPostMsg(hwndDlg, WM_COMMAND, MPFROMSHORT(DID_OK), 0L);
  7528.              break;
  7529.  
  7530.          case WM_COMMAND:
  7531.              switch(COMMANDMSG(&msg)->cmd) {
  7532.                  case DID_OK:
  7533.                      /*
  7534.                          Since the user chose a selection, try to render it.
  7535.                      */
  7536.                      hwndListbox = WinWindowFromID(hwndDlg, IDL_RENDER);
  7537.                      mrItem = WinSendMsg(hwndListbox, LM_QUERYSELECTION, 0L, 0
  7538.                      if (mrItem != (MRESULT) LIT_NONE) {
  7539.                          usFormat = vausFormats[SHORT1FROMMR(mrItem)];
  7540.                          if (usFormat != vusFormat) {
  7541.                              /*
  7542.                                  If the clipboard format is not rendered,
  7543.                                  tell the user.
  7544.                              */
  7545.                              vfUpdate = TRUE;
  7546.                              if (!UpdateScreen(vhwndClient, usFormat)) {
  7547.                                  LOADSTRING(IDS_NODISPLAY, szMessage);
  7548.                                  MESSAGE(szMessage);
  7549.                              }
  7550.                          }
  7551.                      }
  7552.  
  7553.                      /* fall through */
  7554.  
  7555.                  case DID_CANCEL:
  7556.                      WinDismissDlg(hwndDlg, TRUE);
  7557.  
  7558.                  default: break;
  7559.              }
  7560.          default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  7561.      }
  7562.      return FALSE;
  7563.  }
  7564.  
  7565.  MRESULT CALLBACK AboutDlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp
  7566.  {
  7567.  /*
  7568.      About... dialog procedure
  7569.  */
  7570.      switch(msg) {
  7571.          case WM_COMMAND:
  7572.              switch(COMMANDMSG(&msg)->cmd) {
  7573.                  case DID_OK: WinDismissDlg(hwndDlg, TRUE);
  7574.                  default: break;
  7575.              }
  7576.          default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  7577.      }
  7578.      return FALSE;
  7579.  }
  7580.  
  7581.  VOID ReadSelector(HWND hwndMLE, PSZ pszText) {
  7582.  /*
  7583.      Compute the length of the text selector, in bytes.
  7584.      Allocate space, and copy the text selector into an MLE.
  7585.  */
  7586.      IPT ipt;
  7587.      ULONG ulcch = 0;
  7588.      PSZ        pszCounter;
  7589.  
  7590.      pszCounter = pszText;
  7591.      while (*pszCounter++) ulcch++;
  7592.      WinSendMsg(hwndMLE, MLM_FORMAT, MPFROMSHORT(MLFIE_CFTEXT), 0L);
  7593.      WinSendMsg(hwndMLE, MLM_SETIMPORTEXPORT, pszText, (MPARAM) ulcch);
  7594.      WinSendMsg(hwndMLE, MLM_IMPORT, &ipt, (MPARAM) ulcch);
  7595.  }
  7596.  
  7597.  VOID FixFrame(VOID) {
  7598.  /*
  7599.      This routine tells the frame to update the scroll bars.
  7600.  
  7601.      First, make it so that the scroll bars cannot update themselves.
  7602.      Let the frame update the controls.  Then, re-enable the scroll bars.
  7603.  */
  7604.      if (!(vcUpdate--)) {
  7605.          WinEnableWindowUpdate(vhwndHSB, FALSE);
  7606.          WinEnableWindowUpdate(vhwndVSB, FALSE);
  7607.      }
  7608.  
  7609.      WinSendMsg(vhwndClipFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_HORZSCROLL), 0L
  7610.      WinSendMsg(vhwndClipFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_VERTSCROLL), 0L
  7611.  
  7612.      if (!(++vcUpdate)) {
  7613.          WinEnableWindowUpdate(vhwndHSB, TRUE);
  7614.          WinEnableWindowUpdate(vhwndVSB, TRUE);
  7615.      }
  7616.  }
  7617.  
  7618.  VOID NeedScrollBars(BOOL fNeed) {
  7619.  /*
  7620.      This routine hides changes the scroll bar state to correspond with
  7621.      fNeed, showing or hiding them as necessary.
  7622.  */
  7623.      static BOOL fNeeded = TRUE;                /* The last scroll bar state *
  7624.  
  7625.      /*
  7626.          Get the scroll bar handles, if we haven't already.
  7627.      */
  7628.      if (!vhwndHSB) {
  7629.          vhwndHSB = WinWindowFromID(vhwndClipFrame, FID_HORZSCROLL);
  7630.          vhwndVSB = WinWindowFromID(vhwndClipFrame, FID_VERTSCROLL);
  7631.      }
  7632.      /*
  7633.          Case 1:  We need scroll bars, so enable them.
  7634.      */
  7635.      if (fNeed) {
  7636.          if (!fNeeded) {
  7637.              WinSetParent(vhwndHSB, vhwndClipFrame, TRUE);
  7638.              WinSetParent(vhwndVSB, vhwndClipFrame, TRUE);
  7639.              FixFrame();
  7640.          }
  7641.      /*
  7642.          Case 2:  We don't need scroll bars, so hide them.
  7643.      */
  7644.      } else {
  7645.          if (fNeeded) {
  7646.              WinSetParent(vhwndHSB, HWND_OBJECT, TRUE);
  7647.              WinSetParent(vhwndVSB, HWND_OBJECT, TRUE);
  7648.              FixFrame();
  7649.          }
  7650.      }
  7651.      /*
  7652.          Save state for next invocation
  7653.      */
  7654.      fNeeded = fNeed;
  7655.  }
  7656.  
  7657.  /*
  7658.      RenderFormat()
  7659.  
  7660.      Input:                Clipboard format to render, and handle to client ar
  7661.      Side effects:        Renders the image in the client area
  7662.  */
  7663.  BOOL RenderFormat(HWND hwnd, USHORT usFormat) {
  7664.      BOOL    fRendered = TRUE;
  7665.      HMF            hmfCopy;
  7666.      HPS     hpsWindow;
  7667.      LONG    alOptions[8];
  7668.      RECTL   rclWindow;
  7669.      SIZEL   sizl;
  7670.      SWP            swpWindow;
  7671.      ULONG   hItem;
  7672.      POINTL  aptl[3];
  7673.      /*
  7674.          Open the clipboard
  7675.      */
  7676.      if (!WinOpenClipbrd(vhab))
  7677.          return FALSE;
  7678.      /*
  7679.          Open up the window DC and PS
  7680.      */
  7681.      if (!vhdcWindow)
  7682.          vhdcWindow = WinOpenWindowDC(hwnd);
  7683.  
  7684.      sizl.cx = sizl.cy = 0L;
  7685.      hpsWindow = GpiCreatePS(vhab, vhdcWindow, &sizl, GPIA_ASSOC | PU_ARBITRAR
  7686.      /*
  7687.          Enable the scroll bars, if necessary.  This affects the size
  7688.          of the client area.
  7689.      */
  7690.      if (vfUpdate)
  7691.          NeedScrollBars( (vfViewBitmap =
  7692.                  (usFormat == CF_BITMAP) || (usFormat == CF_DSPBITMAP)) );
  7693.  
  7694.      WinQueryWindowRect(hwnd, &rclWindow);
  7695.      /*
  7696.          Get the clipboard data
  7697.      */
  7698.      WinQueryClipbrdFmtInfo(vhab, usFormat, &vfsFmtInfo);
  7699.      if (!(hItem = WinQueryClipbrdData(vhab, usFormat))) {
  7700.          fRendered = FALSE;
  7701.      } else {
  7702.        /*
  7703.          Display the new format, as appropriate.
  7704.        */
  7705.        switch (usFormat) {
  7706.          case CF_TEXT:
  7707.          case CF_DSPTEXT:
  7708.              if (vfUpdate) {
  7709.                  /*
  7710.                      Create a new MLE and read the text into it.
  7711.                  */
  7712.                  vhwndMLE = WinCreateWindow(hwnd, WC_MLE, "",
  7713.                      WS_VISIBLE | MLS_READONLY | MLS_HSCROLL | MLS_VSCROLL,
  7714.                      0, 0,
  7715.                      (SHORT) rclWindow.xRight, (SHORT) rclWindow.yTop,
  7716.                      hwnd, HWND_TOP, 0, NULL, NULL);
  7717.  
  7718.                  ReadSelector(vhwndMLE, MAKEP((SEL) hItem, 0));
  7719.              }
  7720.              break;
  7721.  
  7722.          case CF_BITMAP:
  7723.          case CF_DSPBITMAP:
  7724.              if (vfUpdate) {
  7725.                  /*
  7726.                      Get the BITMAP dimensions, for scroll bar processing
  7727.                  */
  7728.                  if (GpiQueryBitmapParameters((HBITMAP) hItem, &vbmp)
  7729.                          != GPI_OK) {
  7730.                      return FALSE;
  7731.                  }
  7732.                  /*
  7733.                      Set the scroll bar ranges from 0 to vbmp.max - client.max
  7734.                  */
  7735.                  WinQueryWindowPos(hwnd, &swpWindow);
  7736.  
  7737.                  if ((vcMaxHSB = vbmp.cx - swpWindow.cx) < 0)
  7738.                      vcMaxHSB = 0;
  7739.                  if ((vcMaxVSB = vbmp.cy - swpWindow.cy) < 0)
  7740.                      vcMaxVSB = 0;
  7741.                  WinSendMsg(vhwndHSB, SBM_SETSCROLLBAR,
  7742.                      0L, MPFROM2SHORT(0, vcMaxHSB));
  7743.                  WinSendMsg(vhwndVSB, SBM_SETSCROLLBAR,
  7744.                      MPFROMSHORT(vcMaxVSB),
  7745.                      MPFROM2SHORT(0, vcMaxVSB));
  7746.              }
  7747.              /*
  7748.                  Draw the BITMAP, based on the scroll bar settings.
  7749.              */
  7750.              GpiSetBitmap(vhpsMemory, (HBITMAP) hItem);
  7751.  
  7752.              aptl[0].x = rclWindow.xLeft;        /* Target bottom left */
  7753.              aptl[0].y = rclWindow.yBottom;
  7754.              aptl[1].x = rclWindow.xRight;        /* Target top right */
  7755.              aptl[1].y = rclWindow.yTop;
  7756.                                                  /* Source bottom left */
  7757.              aptl[2].x = (LONG) WinSendMsg(vhwndHSB, SBM_QUERYPOS, 0L, 0L);
  7758.              aptl[2].y = vcMaxVSB
  7759.                  - (LONG) WinSendMsg(vhwndVSB, SBM_QUERYPOS, 0L, 0L);
  7760.  
  7761.              GpiBitBlt(hpsWindow, vhpsMemory, 3L, aptl, ROP_SRCCOPY, 0L);
  7762.              GpiSetBitmap(vhpsMemory, NULL);
  7763.              break;
  7764.  
  7765.          case CF_METAFILE:
  7766.          case CF_DSPMETAFILE:
  7767.              /*
  7768.                  Set up the alOptions for displaying the metafile, and
  7769.                  let the system do the rest of the work.
  7770.              */
  7771.              alOptions[PMF_SEGBASE]            = 0L;
  7772.              alOptions[PMF_LOADTYPE]            = LT_DEFAULT;
  7773.              alOptions[PMF_RESOLVE]            = 0L;
  7774.              alOptions[PMF_LCIDS]            = LC_LOADDISC;
  7775.              alOptions[PMF_RESET]            = RES_DEFAULT;
  7776.              alOptions[PMF_SUPPRESS]            = SUP_DEFAULT;
  7777.              alOptions[PMF_COLORTABLES]            = CTAB_NOMODIFY;
  7778.              alOptions[PMF_COLORREALIZABLE]  = CREA_DEFAULT;
  7779.              hmfCopy = GpiCopyMetaFile((HMF) hItem);
  7780.              GpiPlayMetaFile(hpsWindow, hmfCopy, 8L, alOptions, 0L, 0L, NULL);
  7781.              break;
  7782.  
  7783.          case CF_EMPTY:
  7784.              /*
  7785.                  Don't do anything.
  7786.              */
  7787.              break;
  7788.  
  7789.          default:
  7790.              /*
  7791.                  If it's an owner-draw format that we can display...
  7792.                  ...try to get the owner to paint the clipboard.
  7793.                  (return if we were successful or not)
  7794.              */
  7795.              fRendered = SendOwnerMsg(WM_PAINTCLIPBOARD, MPFROMHWND(hwnd), 0L)
  7796.              break;
  7797.        }
  7798.      }
  7799.      /*
  7800.          Tell everybody that the client area is valid now
  7801.      */
  7802.      WinValidateRect(hwnd, (PRECTL) NULL, FALSE);
  7803.      /*
  7804.          Clean up
  7805.      */
  7806.      GpiAssociate(hpsWindow, NULL);
  7807.      GpiDestroyPS(hpsWindow);
  7808.      WinCloseClipbrd(vhab);
  7809.      return fRendered;
  7810.  }
  7811.  
  7812.  BOOL UpdateScreen(HWND hwnd, USHORT usFormat) {
  7813.  /*
  7814.      Render the format, change the title bar.
  7815.      The title bar will look like:  "<appname> (<format>)"
  7816.  */
  7817.      BOOL  fRendered = TRUE;
  7818.      HPS   hpsWindow;
  7819.      RECTL rcl;
  7820.      UCHAR szFormat[MAXLEN];
  7821.      UCHAR szTitle[MAXTITLELEN];
  7822.  
  7823.      if (vfUpdate) {
  7824.          /* If the MLE exists, destroy it */
  7825.          if (vhwndMLE) {
  7826.              WinDestroyWindow(vhwndMLE);
  7827.              vhwndMLE = NULL;
  7828.          }
  7829.  
  7830.          /* Clear the client area */
  7831.          WinQueryWindowRect(hwnd, &rcl);
  7832.          WinInvalidateRect(hwnd, &rcl, FALSE);
  7833.          hpsWindow = WinBeginPaint(hwnd, NULL, NULL);
  7834.          WinFillRect(hpsWindow, &rcl, CLR_BACKGROUND);
  7835.          WinEndPaint(hpsWindow);
  7836.      }
  7837.      if (usFormat)                        // Check that usFormat != CF_EMPTY
  7838.          fRendered = RenderFormat(hwnd, usFormat);
  7839.      /*
  7840.          Set the title bar appropriately
  7841.      */
  7842.      if (!vhwndTitlebar && vhwndClipFrame)
  7843.          vhwndTitlebar = WinWindowFromID(vhwndClipFrame, FID_TITLEBAR);
  7844.  
  7845.      if (vhwndTitlebar) {
  7846.          GetFormatName(usFormat, szFormat);
  7847.          LOADSTRING(IDS_APPNAME, szTitle);
  7848.          strcat(szTitle, "("); strcat(szTitle, szFormat); strcat(szTitle, ")")
  7849.          WinSetWindowText(vhwndTitlebar, szTitle);
  7850.      }
  7851.      /*
  7852.          Save the rendered format.
  7853.      */
  7854.      vusFormat = usFormat;
  7855.      return fRendered;
  7856.  }
  7857.  
  7858.  VOID GetAllFormats(VOID) {
  7859.      USHORT usFormat;                // Temporary used when enumerating
  7860.      /*
  7861.          Put ourselves into a clean state
  7862.      */
  7863.      usFormat = vcFmts = 0;
  7864.      /*
  7865.          Cycle through the available clipboard formats
  7866.      */
  7867.      while (usFormat = WinEnumClipbrdFmts(vhab, usFormat)) {
  7868.          vausFormats[vcFmts++] = usFormat;
  7869.      }
  7870.      /*
  7871.          Set the current clipboard format to the first one, if possible
  7872.          (in preparation for the WM_PAINT which will follow).
  7873.      */
  7874.      vusFormat = (vcFmts ? vausFormats[0] : CF_EMPTY);
  7875.  }
  7876.  
  7877.  VOID GetFormatName(USHORT usFormat, UCHAR szFmtName[]) {
  7878.  /*
  7879.      GetFormatName()
  7880.  
  7881.      This routine returns a format name in szFmtName which corresponds
  7882.      to the format usFormat.  Basically, either we know the format, or
  7883.      we get the name from the system atom table.  If we can't find it,
  7884.      we set it to CF_UNKNOWN.
  7885.  */
  7886.      switch (usFormat) {
  7887.          /*
  7888.              If we know the format, we can read it from the string table.
  7889.          */
  7890.          case CF_EMPTY:
  7891.          case CF_TEXT:
  7892.          case CF_DSPTEXT:
  7893.          case CF_BITMAP:
  7894.          case CF_DSPBITMAP:
  7895.          case CF_METAFILE:
  7896.          case CF_DSPMETAFILE:
  7897.              LOADSTRING(usFormat, szFmtName);
  7898.              break;
  7899.  
  7900.          default:
  7901.              /*
  7902.                  Get the format name from the system atom table.
  7903.                  If not found, tag it as an unknown format.
  7904.              */
  7905.              if (!WinQueryAtomName(WinQuerySystemAtomTable(),
  7906.                     usFormat, szFmtName, MAXLEN))
  7907.  
  7908.                  LOADSTRING(CF_UNKNOWN, szFmtName);
  7909.  
  7910.              break;
  7911.      }
  7912.  }
  7913.  
  7914.  BOOL SendOwnerMsg(USHORT msg, MPARAM mp1, MPARAM mp2) {
  7915.      BOOL    rc;
  7916.      HWND    hwndOwner;
  7917.      /*
  7918.          If we are an OWNERDISPLAY format,
  7919.              lock the owner window, tell it to perform the operation, return
  7920.      */
  7921.      if ( rc = ( (vfsFmtInfo & CFI_OWNERDISPLAY)
  7922.           && (hwndOwner = WinQueryClipbrdOwner(vhab, TRUE)) ) ) {
  7923.  
  7924.          WinSendMsg(hwndOwner, msg, mp1, mp2);
  7925.          WinLockWindow(hwndOwner, FALSE);
  7926.      }
  7927.      return rc;
  7928.  }
  7929.  
  7930.  BOOL DoScrolling(HWND hwnd, BOOL fHorz, USHORT sbCmd) {
  7931.  /*
  7932.      This routine depends on the fact that the thumb cannot be set past the
  7933.      range of the scroll bar.  Since this is handled in the system SBM_SETPOS
  7934.      code already, we need not worry about it.
  7935.  
  7936.      We return TRUE if the scroll bar message is processed.
  7937.  */
  7938.      HWND   hwndSB;                /* Scroll bar handle */
  7939.      USHORT cpels;                /* Page length/width for PAGExxxx commands *
  7940.      SWP    swp;                        /* Dimensions of the client area */
  7941.      USHORT usOld;                /* The current scroll bar position */
  7942.      USHORT usNew;                /* The new scroll bar position */
  7943.      /*
  7944.          Set the scroll bar-specific parameters
  7945.      */
  7946.      WinQueryWindowPos(hwnd, &swp);
  7947.      if (fHorz) {        /* Horizontal scroll bar */
  7948.          hwndSB = vhwndHSB;
  7949.          cpels = swp.cx;
  7950.      } else {                /* Vertical scroll bar */
  7951.          hwndSB = vhwndVSB;
  7952.          cpels = swp.cy;
  7953.      }
  7954.      /*
  7955.          Handle both scroll bars with one common routine
  7956.  
  7957.          Basically, the scroll bar has been set so that
  7958.          the thumb value corresponds to the offset that
  7959.          the bitmap is drawn from.  So, to scroll by a
  7960.          page, compute the number of pels of the page,
  7961.          and move the thumb by that amount.
  7962.  
  7963.          This code is simplified by the fact that SB_SETPOS
  7964.          will not allow the thumb to be set outside of the
  7965.          range of the scroll bar, but will "stop" it at the
  7966.          appropriate bound.
  7967.      */
  7968.      usOld = SHORT1FROMMR( WinSendMsg(hwndSB, SBM_QUERYPOS, 0L, 0L));
  7969.  
  7970.      switch (sbCmd) {
  7971.          case SB_PAGERIGHT:        /* SB_PAGEDOWN */
  7972.              WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld + cpels), 0L);
  7973.              break;
  7974.  
  7975.          case SB_PAGELEFT:        /* SB_PAGEUP */
  7976.              WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld - cpels), 0L);
  7977.              break;
  7978.  
  7979.          case SB_LINERIGHT:        /* SB_LINEDOWN */
  7980.              WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld + LINE), 0L);
  7981.              break;
  7982.  
  7983.          case SB_LINELEFT:        /* SB_LINEUP */
  7984.              WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(usOld - LINE), 0L);
  7985.              break;
  7986.  
  7987.          case SB_SLIDERPOSITION:
  7988.              /*
  7989.                  It would be nice to be consistent with the other
  7990.                  SB_ cases, but the problem is that when this message
  7991.                  is sent, the position is *already* set to "usPosition".
  7992.  
  7993.                  So, just invalidate the entire region, and hope that most
  7994.                  of these types of operations will be large scrolls.
  7995.              */
  7996.              // WinSendMsg(hwndSB, SBM_SETPOS, MPFROMSHORT(LOUSHORT(mp2)), 0L)
  7997.              WinInvalidateRect(hwnd, NULL, TRUE);
  7998.              break;
  7999.  
  8000.          default:
  8001.              return FALSE;
  8002.      }
  8003.      /*
  8004.          Now, we find out where the new thumb position is,
  8005.          scroll the window contents appropriately, and specify
  8006.          SW_INVALIDATERGN so that the remainder will be
  8007.          invalidated/repainted.
  8008.      */
  8009.      usNew = SHORT1FROMMR( WinSendMsg(hwndSB, SBM_QUERYPOS, 0L, 0L));
  8010.      if (fHorz)
  8011.          WinScrollWindow(hwnd, (SHORT) (usOld - usNew), 0,
  8012.              NULL, NULL, NULL, NULL, SW_INVALIDATERGN);
  8013.      else
  8014.          WinScrollWindow(hwnd, 0, (SHORT) (usNew - usOld),
  8015.              NULL, NULL, NULL, NULL, SW_INVALIDATERGN);
  8016.  
  8017.      return TRUE;
  8018.  }
  8019.  
  8020.  
  8021.  CLOCK.C
  8022.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CLOCK\CLOCK.C
  8023.  
  8024.  /*
  8025.      clock.c        Presentation Manager Analog Clock Application
  8026.      Created by Microsoft Corporation, 1989
  8027.  */
  8028.  #define INCL_PM
  8029.  #include <os2.h>
  8030.  #include <string.h>
  8031.  #include "res.h"
  8032.  
  8033.  extern MRESULT EXPENTRY ClkWndProc ( HWND , USHORT , MPARAM , MPARAM ) ;
  8034.  
  8035.  int cdecl main ( int argc , char * argv [ ] ) ;
  8036.  BOOL ClkInit ( VOID ) ;
  8037.  HWND hwndFrame ;
  8038.  HAB hab ;
  8039.  HMQ hmq ;
  8040.  HSWITCH hsw ;
  8041.  extern HPS hps ;
  8042.  BOOL fStartAsIcon = FALSE ;
  8043.  
  8044.  /*
  8045.      main(argc, argv)        Main program
  8046.  */
  8047.  int cdecl main ( int argc , char * argv [ ] )
  8048.  {
  8049.      QMSG qmsg ;
  8050.  
  8051.      /* have we been asked to start ourselves as an icon? */
  8052.      if (argc > 0) {
  8053.          if ( strcmpi ( argv [ 1 ] , "iconic" ) == 0 )
  8054.              fStartAsIcon = TRUE ;
  8055.      }
  8056.  
  8057.      if ( ClkInit ( ) ) {
  8058.  
  8059.          while ( WinGetMsg ( hab , & qmsg , NULL , 0 , 0 ) )
  8060.              WinDispatchMsg ( hab , & qmsg ) ;
  8061.  
  8062.          /* Clean up code */
  8063.          GpiDestroyPS( hps );
  8064.          WinRemoveSwitchEntry ( hsw ) ;
  8065.          WinDestroyWindow ( hwndFrame ) ;
  8066.          WinDestroyMsgQueue ( hmq ) ;
  8067.          WinTerminate ( hab ) ;
  8068.      }
  8069.  
  8070.      return 0 ;
  8071.  }
  8072.  
  8073.  /*
  8074.      ClkInit()                Clock Initialization routine
  8075.      Returns TRUE if successful.
  8076.  */
  8077.  BOOL ClkInit ( )
  8078.  {
  8079.      /* application name, switch list info, and frame creation flags */
  8080.      static PSZ pszClkName = "Clock" ;
  8081.      static SWCNTRL swctl = { 0 , 0 , 0 , 0 , 0 , SWL_VISIBLE ,
  8082.                               SWL_JUMPABLE , "Clock" , 0 } ;
  8083.      static LONG fcf = FCF_SIZEBORDER | FCF_TITLEBAR | FCF_MINMAX
  8084.                        | FCF_SYSMENU ;
  8085.  
  8086.      HWND hwndClient ;
  8087.      PID pid ;
  8088.      TID tid ;
  8089.  
  8090.      if ( ( hab = WinInitialize ( 0 ) ) == NULL )
  8091.          return FALSE ;
  8092.  
  8093.      if ( ( hmq = WinCreateMsgQueue ( hab , 0 ) ) == NULL ) {
  8094.          WinTerminate ( hab ) ;
  8095.          return FALSE ;
  8096.      }
  8097.  
  8098.      if ( ! WinRegisterClass ( hab , pszClkName , ClkWndProc ,
  8099.                                CS_SIZEREDRAW , 0 ) ) {
  8100.          WinDestroyMsgQueue ( hmq ) ;
  8101.          WinTerminate ( hab ) ;
  8102.          return FALSE ;
  8103.      }
  8104.  
  8105.      hwndFrame = WinCreateStdWindow ( HWND_DESKTOP , ( ULONG ) NULL , & fcf ,
  8106.                                       pszClkName , pszClkName , WS_VISIBLE ,
  8107.                                       (HMODULE) NULL , ID_RESOURCE , & hwndCli
  8108.  
  8109.      if ( hwndFrame == NULL ) {
  8110.          WinDestroyMsgQueue ( hmq ) ;
  8111.          WinTerminate ( hab ) ;
  8112.          return FALSE ;
  8113.      }
  8114.  
  8115.      /* add ourselves to the switch list */
  8116.      WinQueryWindowProcess ( hwndFrame , & pid , & tid ) ;
  8117.      swctl . hwnd = hwndFrame ;
  8118.      swctl . idProcess = pid ;
  8119.      hsw = WinAddSwitchEntry ( & swctl ) ;
  8120.  
  8121.      return TRUE ;
  8122.  }
  8123.  
  8124.  
  8125.  COMPORT.C
  8126.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\COMTALK\COMPORT.C
  8127.  
  8128.  /*
  8129.     comport.c -- This file contains the sources for COM port manipulation.
  8130.     Created by Microsoft Corporation, 1989
  8131.  */
  8132.  #define  INCL_DOSFILEMGR
  8133.  #define         INCL_DOSDEVICES
  8134.  #define         INCL_DOSDEVIOCTL
  8135.  #include <os2.h>
  8136.  #include "global.h"
  8137.  #include "comport.h"
  8138.  /*
  8139.     Constants
  8140.  */
  8141.         XON        0x11        /* Ctrl Q */
  8142.         XOFF        0x13        /* Ctrl S */
  8143.  char        CRLF[2] = { 0x0d, 0x0a };
  8144.  
  8145.  /*
  8146.      Variables
  8147.  */
  8148.  DCBINFO                dcbinfo;        /* Device control block for Ioctl 53H,
  8149.  HFILE                hPort;
  8150.  LINECONTROL        lnctlBuf;
  8151.  int                rc;
  8152.  USHORT                usErrWord;
  8153.  
  8154.  int ComFlush(void) {
  8155.  /*
  8156.      Flush the COM port with Category 11 functions
  8157.  */
  8158.      BYTE Data, Zero = 0;
  8159.  
  8160.      /* Call Category 11 Functions 1H, 2H  Flush Input, Output Buffers */
  8161.      if (rc = DosDevIOCtl(&Data, &Zero, 0x01, 11, hPort)) return rc;
  8162.      if (rc = DosDevIOCtl(&Data, &Zero, 0x02, 11, hPort)) return rc;
  8163.      return 0;
  8164.  }
  8165.  
  8166.  int ComInit(COM comTerm) {
  8167.  /*
  8168.      Open the COM port according to the specifications
  8169.  */
  8170.      USHORT action;
  8171.  
  8172.      /* Get File Handle for COM port (shared read/write access) */
  8173.      if (rc = DosOpen(comTerm.szPort,&hPort, &action, 0L, 0, 0x0001, 0x0042, 0
  8174.          return rc;
  8175.  
  8176.      /* Call Category 1 Function 41H   Set Baud Rate */
  8177.      if (rc = DosDevIOCtl(NULL, &comTerm.usBaud, 0x41, 1, hPort)) return rc;
  8178.  
  8179.      /* Call Category 1 Function 42H   Set Line Characteristics */
  8180.      lnctlBuf.bDataBits        = comTerm.bData;
  8181.      lnctlBuf.bParity        = comTerm.bParity;
  8182.      lnctlBuf.bStopBits        = (BYTE) (comTerm.bStop - 20);        /* IDD_ON
  8183.      if (rc = DosDevIOCtl(NULL, &lnctlBuf, 0x42, 1, hPort)) return rc;
  8184.  
  8185.      /* Call Category 1 Function 73H   Query Device Control Block */
  8186.      if (rc = DosDevIOCtl(&dcbinfo, 0L, 0x73, 1, hPort)) return rc;
  8187.  
  8188.      /*
  8189.          Do we want software handshaking?
  8190.      */
  8191.      dcbinfo.fbFlowReplace        &= ~(0x03);        /* Clear bits 0 and 1 */
  8192.      dcbinfo.fbFlowReplace        |=
  8193.          (comTerm.fSoftware)        ? (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE)
  8194.      /*
  8195.          Do we want hardware handshaking?
  8196.      */
  8197.      /* Turn on DTR, if appropriate */
  8198.      dcbinfo.fbCtlHndShake        &= ~(0x03);        /* Clear bits 0 and 1 */
  8199.      dcbinfo.fbCtlHndShake        |= ((comTerm.fHardware) ? MODE_DTR_CONTROL :
  8200.  
  8201.      /* Turn on RTS, if appropriate */
  8202.      dcbinfo.fbFlowReplace        &= ~(0xc0);        /* Clear bits 6 and 7 */
  8203.      dcbinfo.fbFlowReplace        |= ((comTerm.fHardware) ? MODE_RTS_CONTROL :
  8204.  
  8205.      /* Adjust CTS output handshaking */
  8206.      dcbinfo.fbCtlHndShake        &= ~MODE_CTS_HANDSHAKE;     /* Clear bit 3 *
  8207.      dcbinfo.fbCtlHndShake        |= ((comTerm.fHardware)?MODE_CTS_HANDSHAKE:0
  8208.  
  8209.      /* Adjust DSR output handshaking */
  8210.      dcbinfo.fbCtlHndShake        &= ~MODE_DSR_HANDSHAKE;     /* Clear bit 4 *
  8211.      dcbinfo.fbCtlHndShake        |= ((comTerm.fHardware)?MODE_DSR_HANDSHAKE:0
  8212.  
  8213.      /* Turn off DCD output handshaking */
  8214.      dcbinfo.fbCtlHndShake        &= ~MODE_DCD_HANDSHAKE;     /* Clear bit 5 *
  8215.  
  8216.      /* Adjust DSR input sensitivity */
  8217.      dcbinfo.fbCtlHndShake        &= ~MODE_DSR_SENSITIVITY;   /* Clear bit 6 *
  8218.      dcbinfo.fbCtlHndShake        |= ((comTerm.fHardware)?MODE_DSR_SENSITIVITY
  8219.      /*
  8220.          Set the line to Wait for Character, Read mode
  8221.      */
  8222.      dcbinfo.fbTimeout                &= ~(0x06);        /* Clear bits, then s
  8223.      dcbinfo.fbTimeout                |= MODE_WAIT_READ_TIMEOUT;
  8224.      dcbinfo.usReadTimeout        = -1;                /* Never! */
  8225.  
  8226.      /* Call Category 1 Function 53H   Set Device Control Block */
  8227.      if (rc = DosDevIOCtl(0L, &dcbinfo, 0x53, 1, hPort)) return rc;
  8228.  
  8229.      /* Get ready to start */
  8230.      return ComFlush();
  8231.  }
  8232.  
  8233.  USHORT ComRead(Line pli) {
  8234.  /*
  8235.      Reads all characters present
  8236.      Returns:        0 if successful
  8237.                  nonzero (Dos Error or Com Error Word) if unsuccessful
  8238.  */
  8239.      /* Read from the port... And snatch as many as you can! (blocking read) *
  8240.      if (rc = DosRead(hPort, pli->szText, MAXLINELEN, &(pli->cch))) return rc;
  8241.  
  8242.      /* Check the COM Error Word */
  8243.      if (rc = DosDevIOCtl(&usErrWord, NULL, 0x6d, 1, hPort)) return rc;
  8244.  
  8245.      /* ...then return it */
  8246.      return usErrWord;
  8247.  }
  8248.  
  8249.  int ComWrite(char ch) {
  8250.  /*
  8251.      Write a character at a time
  8252.  
  8253.      Okay as long as you don't type too fast
  8254.  */
  8255.      USHORT nCharsWritten;
  8256.  
  8257.      return DosWrite(hPort, &ch, 1, &nCharsWritten);
  8258.  }
  8259.  
  8260.  int ComClose(void) {
  8261.  /*
  8262.      Close the COM port
  8263.  */
  8264.      if (rc = ComFlush()) return rc;
  8265.      return DosClose(hPort);
  8266.  }
  8267.  
  8268.  int ComBreak(void) {
  8269.  /*
  8270.      Set BREAK mode ON
  8271.  */
  8272.      USHORT ComErr;
  8273.  
  8274.      /* Call Category 1 Function 4BH -- Set Break On */
  8275.      return DosDevIOCtl(&ComErr, NULL, 0x4b, 1, hPort);
  8276.  }
  8277.  
  8278.  int ComUnbreak(void) {
  8279.  /*
  8280.      Set BREAK mode OFF
  8281.  */
  8282.      USHORT ComErr;
  8283.  
  8284.      /* Call Category 1 Function 45H -- Set Break Off */
  8285.      return DosDevIOCtl(&ComErr, NULL, 0x45, 1, hPort);
  8286.  }
  8287.  
  8288.  int ComError(void) { return (int) usErrWord; }
  8289.  
  8290.  
  8291.  COMTALK.C
  8292.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\COMTALK\COMTALK.C
  8293.  
  8294.  /*
  8295.     comtalk.c -- Main routines
  8296.     Created by Microsoft Corporation, 1989
  8297.  
  8298.     This file contains the sources for the dialog box manipulation, and menu
  8299.     managment, and other aspects of interfacing with the user.
  8300.  */
  8301.  #define INCL_WIN
  8302.  #include <os2.h>
  8303.  "comtalk.h"        /* definition of COM from Global, and Resource IDs */
  8304.  "avio.h"        /* Routines needed to manage AVIO Presentation Space */
  8305.  "threads.h"        /* Thread initialization and control routines */
  8306.  <stdio.h>        /* Only needed for file I/O */
  8307.  <string.h>        /* one strcpy call */
  8308.  /*
  8309.      Variables
  8310.  */
  8311.  CHAR                 szCaption[] = "";
  8312.  HAB                hAB;
  8313.  COM                comTerm;
  8314.  COM                comTemp;
  8315.  HWND                hWndMenu;
  8316.  CLASSINFO        clsi;
  8317.  PFNWP                pfnOldFrameWndProc;
  8318.  BOOL                fConnected        = FALSE;
  8319.  BOOL                fPaging;
  8320.  int                iUpdate;
  8321.  BOOL                fFreeze                = TRUE;
  8322.  int                iError;
  8323.  /*
  8324.      Macros
  8325.  */
  8326.  #define InRange(x, a, b) ((x >= a) && (x <= b))
  8327.  
  8328.  /*
  8329.      Shorthand for sending messages, querying
  8330.  */
  8331.  #define Parent(h) \
  8332.      WinQueryWindow(h, QW_PARENT, FALSE)
  8333.  
  8334.  #define EnableMenuItem(id) \
  8335.      WinSendMsg(hWndMenu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE), \
  8336.                 MPFROM2SHORT(MIA_DISABLED,0))
  8337.  
  8338.  #define DisableMenuItem(id) \
  8339.      WinSendMsg(hWndMenu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE), \
  8340.                 MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED))
  8341.  
  8342.  #define CheckMenuItem(id) \
  8343.      WinSendMsg(hWndMenu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE), \
  8344.                 MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED))
  8345.  
  8346.  #define UnCheckMenuItem(id) \
  8347.      WinSendMsg(hWndMenu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE), \
  8348.                 MPFROM2SHORT(MIA_CHECKED, 0))
  8349.  
  8350.  #define PushButton(h, id) \
  8351.      WinSendDlgItemMsg(h, id, BM_SETCHECK, MPFROM2SHORT(TRUE, 0), 0L)
  8352.  
  8353.  #define Valid(bData, bStop) \
  8354.      (((bData == IDD_FIVE) && (bStop != IDD_TWOSTOP)) \
  8355.      || ((bData != IDD_FIVE) && (bStop != IDD_ONEFIVE)))
  8356.  
  8357.  #define ErrMsg(h, s) \
  8358.      WinMessageBox(HWND_DESKTOP, h, s, NULL, 0, MB_OK | MB_ICONEXCLAMATION)
  8359.  
  8360.  char Ctrl(char ch) {
  8361.      return  (CHAR) ((('a' <= ch) && (ch <= 'z')) ?  (ch - 'a' + '\001') :
  8362.            ((('A' <= ch) && (ch <= 'Z')) ? (ch - 'A' + '\001') : ch));
  8363.  }
  8364.  
  8365.  /*
  8366.      Local/Private routines
  8367.  */
  8368.  void ReadOpts(HWND);
  8369.  void InitTerm(void);
  8370.  void Initialize(HWND);
  8371.  void ChangeSystemMenu(HWND);
  8372.  BOOL Filter(USHORT, char, USHORT);
  8373.  
  8374.  void main (void) {
  8375.       static CHAR szClientClass[] = "Terminal";
  8376.       HMQ        hmq;
  8377.       HWND        hWndClient, hWndFrame;
  8378.       QMSG        qmsg;
  8379.       ULONG        flFrameFlags = FCF_STANDARD | FCF_HORZSCROLL | FCF_VERTSCRO
  8380.       ULONG         flFrameStyle = WS_VISIBLE | FS_SCREENALIGN;
  8381.  
  8382.       hAB = WinInitialize(0);
  8383.       hmq = WinCreateMsgQueue(hAB, 0);
  8384.  
  8385.       WinRegisterClass(hAB, szClientClass, ClientWndProc, CS_SYNCPAINT, 0);
  8386.  
  8387.       hWndFrame = WinCreateStdWindow(HWND_DESKTOP, flFrameStyle,
  8388.                                      &flFrameFlags, szClientClass, szCaption,
  8389.                                       0L, (HMODULE) NULL, ID_RESOURCE, &hWndCl
  8390.  
  8391.       /* Setup AVIO PS and force a paint */
  8392.       AvioInit(hWndFrame, hWndClient);
  8393.       WinSendMsg(hWndClient, WM_PAINT, NULL, NULL);
  8394.  
  8395.       /* Try to subclass the Frame window... */
  8396.       pfnOldFrameWndProc = WinSubclassWindow(hWndFrame, NewFrameWndProc);
  8397.  
  8398.       while (WinGetMsg(hAB, &qmsg, NULL, 0, 0)) WinDispatchMsg(hAB, &qmsg);
  8399.  
  8400.       /* Blast the AVIO PS */
  8401.       AvioClose();
  8402.  
  8403.       WinDestroyWindow(hWndFrame);
  8404.       WinDestroyMsgQueue(hmq);
  8405.       WinTerminate(hAB);
  8406.       DosExit(EXIT_PROCESS, 0);
  8407.  }
  8408.  
  8409.  MRESULT CALLBACK ClientWndProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  8410.  /*
  8411.       Window Procedure which traps messages to the Client area
  8412.  */
  8413.       switch (msg) {
  8414.            case WM_AVIOUPDATE:
  8415.                  fNoUpdate = AvioUpdateLines(FALSE, &fPaging);
  8416.                  if (fConnected && fPaging) {
  8417.                      CheckMenuItem(IDM_PAGING);
  8418.                  }
  8419.                  break;
  8420.  
  8421.            case WM_MSGBOX:
  8422.                  iUpdate = (int)SHORT1FROMMP( mp2);
  8423.                  switch ((int)SHORT1FROMMP(mp1)) {
  8424.                      case (int) MBE_COMREAD:
  8425.                          if (iError = iUpdate) EnableMenuItem(IDM_ERRORS);
  8426.                          iUpdate = 0;
  8427.                          break;
  8428.  
  8429.                      default:
  8430.                          ErrMsg(hWnd, aszMessage[SHORT1FROMMP(mp1)]);
  8431.                          break;
  8432.                  }
  8433.                  if (iUpdate) {        /* Page down because queue is full */
  8434.                      fNoUpdate = AvioUpdateLines(TRUE, &fPaging);
  8435.                      if (fConnected && fPaging) CheckMenuItem(IDM_PAGING);
  8436.                      else UnCheckMenuItem(IDM_PAGING);
  8437.                      ThdReset();
  8438.                  }
  8439.                  break;
  8440.  
  8441.            case WM_CREATE:
  8442.                  ChangeSystemMenu(hWnd);
  8443.                  /*
  8444.                      Initialize the Dialog Options
  8445.                  */
  8446.                  Initialize(hWnd);
  8447.                  /*
  8448.                      Get the Handle so you can enable/disable menu items
  8449.                      Thanks again to Charles Petzold
  8450.                  */
  8451.                  hWndMenu = WinWindowFromID(Parent(hWnd), FID_MENU);
  8452.                  /*
  8453.                      Disable some entries (can do this in the resource file)
  8454.                  */
  8455.                  DisableMenuItem(IDM_CLOSE);
  8456.                  DisableMenuItem(IDM_BREAK);
  8457.                  DisableMenuItem(IDM_COMMANDMENU);
  8458.                  break;
  8459.  
  8460.            case WM_PAINT:                /* Paint the AVIO way! */
  8461.                  AvioPaint(hWnd);
  8462.                  break;
  8463.  
  8464.            case WM_SIZE:                        /* Size the AVIO way!  */
  8465.                  fNoUpdate = AvioUpdateLines(FALSE, &fPaging);
  8466.                  if (fConnected && fPaging) {
  8467.                      CheckMenuItem(IDM_PAGING);
  8468.                  }
  8469.                  return AvioSize(hWnd, msg, mp1, mp2);
  8470.                  break;
  8471.  
  8472.            case WM_HSCROLL:
  8473.                  AvioScroll(HIUSHORT(mp2), LOUSHORT(mp2), TRUE);
  8474.                  break;
  8475.  
  8476.            case WM_VSCROLL:
  8477.                  AvioScroll(HIUSHORT(mp2), LOUSHORT(mp2), FALSE);
  8478.                  break;
  8479.  
  8480.            case WM_ERASEBACKGROUND:
  8481.                  return 0;
  8482.                  break;
  8483.  
  8484.            case WM_COMMAND:
  8485.                  switch (COMMANDMSG(&msg)->cmd) {
  8486.                      case IDM_ABOUT:
  8487.                          WinDlgBox(HWND_DESKTOP, hWnd, AboutDlgProc,
  8488.                                    (HMODULE) NULL, IDD_ABOUT, NULL);
  8489.                          return 0;
  8490.  
  8491.                      case IDM_HELP:
  8492.                          WinDlgBox(HWND_DESKTOP, hWnd, AboutDlgProc,
  8493.                                    (HMODULE) NULL, IDD_MAINHELPBOX, NULL);
  8494.                          return 0;
  8495.  
  8496.                      case IDM_SETTINGS:
  8497.                          WinDlgBox(HWND_DESKTOP, hWnd, SetDlgProc,
  8498.                                    (HMODULE) NULL, IDD_SET, NULL);
  8499.                          return 0;
  8500.  
  8501.                      case IDM_CONNECT:
  8502.                          AvioStartup(hWnd);
  8503.                          ThdInitialize(hWnd, comTerm);        /* Spawn 3 threa
  8504.                          /*
  8505.                              Disable/Enable Menu Items
  8506.                          */
  8507.                          DisableMenuItem(IDM_CONNECT);
  8508.                          DisableMenuItem(IDM_SETTINGS);
  8509.                          DisableMenuItem(IDM_ERRORS);
  8510.  
  8511.                          EnableMenuItem(IDM_CLOSE);
  8512.                          EnableMenuItem(IDM_BREAK);
  8513.                          EnableMenuItem(IDM_COMMANDMENU);
  8514.                          fConnected = TRUE;
  8515.                          return 0;
  8516.  
  8517.                      case IDM_CLOSE:
  8518.                          fConnected = FALSE;
  8519.                          ThdTerminate();                /* Might have to wait?
  8520.                          /*
  8521.                              Update menu items
  8522.                          */
  8523.                          UnCheckMenuItem(IDM_BREAK);
  8524.  
  8525.                          DisableMenuItem(IDM_CLOSE);
  8526.                          DisableMenuItem(IDM_BREAK);
  8527.                          DisableMenuItem(IDM_COMMANDMENU);
  8528.  
  8529.                          EnableMenuItem(IDM_CONNECT);
  8530.                          EnableMenuItem(IDM_SETTINGS);
  8531.  
  8532.                          return 0;
  8533.  
  8534.                      case IDM_BREAK:
  8535.                          ThdDoBreak();
  8536.                          return 0;
  8537.  
  8538.                      case IDM_ERRORS:
  8539.                          if (iError & 1)
  8540.                              ErrMsg(hWnd, "Receive Queue Overrun");
  8541.                          if (iError & 2)
  8542.                              ErrMsg(hWnd, "Receive Hardware Overrun");
  8543.                          if (iError & 4)
  8544.                              ErrMsg(hWnd, "Parity Error");
  8545.                          if (iError & 8)
  8546.                              ErrMsg(hWnd, "Framing Error");
  8547.                          DisableMenuItem(IDM_ERRORS);
  8548.                          return 0;
  8549.  
  8550.                      case IDM_PAGE:
  8551.                          fNoUpdate = AvioUpdateLines(TRUE, &fPaging);
  8552.                          if (fPaging) CheckMenuItem(IDM_PAGING);
  8553.                          else UnCheckMenuItem(IDM_PAGING);
  8554.                          return 0;
  8555.  
  8556.                      case IDM_UP:
  8557.                          AvioPageUp();
  8558.                          return 0;
  8559.  
  8560.                      case IDM_PAGING:
  8561.                          if (fPaging = !fPaging) {
  8562.                              CheckMenuItem(IDM_PAGING);
  8563.                          } else {
  8564.                              UnCheckMenuItem(IDM_PAGING);
  8565.                          }
  8566.                          return 0;
  8567.  
  8568.                      default: return 0;
  8569.                  }
  8570.  
  8571.            case WM_CHAR:                /* Put characters in typeahead buffer
  8572.                  if (fConnected && !(CHARMSG(&msg)->fs & KC_KEYUP))
  8573.                      if (Filter( CHARMSG(&msg)->fs,
  8574.                           (char)        CHARMSG(&msg)->chr,
  8575.                                  CHARMSG(&msg)->vkey))
  8576.                          ErrMsg(hWnd, "Error Writing COM Port");
  8577.                  break;
  8578.  
  8579.            case WM_TRACKFRAME:
  8580.                  AvioTrackFrame(hWnd, mp1);
  8581.                  break;
  8582.  
  8583.            case WM_MINMAXFRAME: /* Trap MAXIMIZE messages */
  8584.                  AvioMinMax((PSWP) mp1);
  8585.  
  8586.            default: return WinDefWindowProc(hWnd, msg, mp1, mp2);
  8587.       }
  8588.       return 0;
  8589.  }
  8590.  
  8591.  MRESULT CALLBACK AboutDlgProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  8592.  /*
  8593.      Dialog box control for the ABOUT COMTALK... dialog box
  8594.  */
  8595.      switch(msg) {
  8596.          case WM_COMMAND:
  8597.              switch(COMMANDMSG(&msg)->cmd) {
  8598.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  8599.                  default: break;
  8600.              }
  8601.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  8602.      }
  8603.      return FALSE;
  8604.  }
  8605.  
  8606.  void WriteOpts(void) {
  8607.  /*
  8608.      Write Settings to file COMTALK.INI
  8609.  */
  8610.      FILE *fp;
  8611.  
  8612.      fp = fopen("comtalk.ini", "w+");
  8613.      fprintf(fp, "%d %d %d %d %d %d %d %s\n", comTerm.usBaud, comTerm.bParity,
  8614.                  comTerm.bData, comTerm.bStop, comTerm.fWrap,
  8615.                  comTerm.fHardware, comTerm.fSoftware, comTerm.szPort);
  8616.      fclose(fp);
  8617.  }
  8618.  
  8619.  void ReadOpts(HWND hWnd) {
  8620.  /*
  8621.      Read Settings from COMTALK.INI
  8622.  */
  8623.      FILE *fp;
  8624.  
  8625.      /* Use InitTerm() if we have reading problems */
  8626.      if ((fp = fopen("comtalk.ini", "r")) == NULL) InitTerm();
  8627.      else if (fscanf(fp, "%d%d%d%d%d%d%d%s", &comTerm.usBaud, &comTerm.bParity
  8628.          &comTerm.bData, &comTerm.bStop, &comTerm.fWrap,
  8629.          &comTerm.fHardware, &comTerm.fSoftware, comTerm.szPort) == EOF)
  8630.          InitTerm();
  8631.      if (!Valid(comTerm.bData, comTerm.bStop)) {
  8632.          ErrMsg(hWnd, "Invalid terminal setting");
  8633.          InitTerm();
  8634.      }
  8635.      fclose(fp);
  8636.  }
  8637.  
  8638.  void InitTerm(void) {
  8639.  /*
  8640.      Initialize the TERM structure to DosDevIOCtl defaults
  8641.  */
  8642.      strcpy(comTerm.szPort, "com1");
  8643.      comTerm.usBaud = 9600; comTerm.bParity = IDD_EVENP;
  8644.      comTerm.bData = IDD_SEVEN; comTerm.bStop = IDD_ONESTOP;
  8645.      comTerm.fWrap = comTerm.fSoftware = TRUE; comTerm.fHardware = FALSE;
  8646.  }
  8647.  
  8648.  MRESULT CALLBACK SetDlgProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2) {
  8649.  /*
  8650.      The Settings Dialog Box control routine
  8651.  */
  8652.      BOOL        rc;
  8653.      BYTE        bTemp;
  8654.  
  8655.      switch(msg) {
  8656.          case WM_INITDLG:
  8657.              WinSetDlgItemText(hDlg, IDD_PORT, comTerm.szPort);
  8658.              WinSetDlgItemShort(hDlg, IDD_BAUD, comTerm.usBaud, FALSE);
  8659.  
  8660.              PushButton(hDlg, comTerm.bParity);
  8661.              PushButton(hDlg, comTerm.bData);
  8662.              PushButton(hDlg, comTerm.bStop);
  8663.              if (comTerm.fWrap) PushButton(hDlg, IDD_WRAP);
  8664.              if (comTerm.fHardware) PushButton(hDlg, IDD_HW);
  8665.              if (comTerm.fSoftware) PushButton(hDlg, IDD_SW);
  8666.  
  8667.              comTemp.bParity        = comTerm.bParity;
  8668.              comTemp.bData        = comTerm.bData;
  8669.              comTemp.bStop        = comTerm.bStop;
  8670.              comTemp.fWrap        = comTerm.fWrap;
  8671.              comTemp.fHardware        = comTerm.fHardware;
  8672.              comTemp.fSoftware   = comTerm.fSoftware;
  8673.              break;
  8674.  
  8675.          case WM_HELP:
  8676.              WinDlgBox(HWND_DESKTOP, hDlg, AboutDlgProc,
  8677.                        (HMODULE) NULL, IDD_SETHELPBOX, NULL);
  8678.              break;
  8679.  
  8680.          case WM_CONTROL:
  8681.              /*
  8682.                  The fact that these are AutoRadioButtons makes life easy.
  8683.              */
  8684.              bTemp = (BYTE) SHORT1FROMMP(mp1);        /* Which button pushed?
  8685.              if InRange(bTemp, IDD_NOP, IDD_SPACEP)
  8686.                   {
  8687.                          comTemp.bParity = bTemp;
  8688.              }
  8689.                  else
  8690.                  {
  8691.                          if InRange(bTemp, IDD_FIVE, IDD_EIGHT)
  8692.                          {
  8693.                                  comTemp.bData = bTemp;
  8694.                      }
  8695.                          else
  8696.                          {
  8697.                                  if InRange(bTemp, IDD_ONESTOP, IDD_TWOSTOP)
  8698.                                  {
  8699.                                          comTemp.bStop = bTemp;
  8700.                                  }
  8701.                               else
  8702.                                  {
  8703.                                          switch (bTemp) {
  8704.                                          case IDD_WRAP: comTemp.fWrap     = !c
  8705.                                          case IDD_HW  : comTemp.fHardware = !c
  8706.                                          case IDD_SW  : comTemp.fSoftware = !c
  8707.                                          default:
  8708.                                      }
  8709.                                  }
  8710.                          }
  8711.                  }
  8712.              break;
  8713.          case WM_COMMAND:        /* Ready to exit... */
  8714.              switch(COMMANDMSG(&msg)->cmd) {
  8715.                  case IDD_SAVE:
  8716.                  case DID_OK:
  8717.                      if (!Valid(comTemp.bData, comTemp.bStop)) {
  8718.                          ErrMsg(hDlg,"Data and Stop Bits Incompatible");
  8719.                          break;        /* No-op...Dialog not dismissed */
  8720.                      }
  8721.                      WinQueryDlgItemText(hDlg, IDD_PORT, 5, comTerm.szPort);
  8722.                      WinQueryDlgItemShort(hDlg, IDD_BAUD, &comTerm.usBaud, rc)
  8723.                      comTerm.bParity        = comTemp.bParity;
  8724.                      comTerm.bData        = comTemp.bData;
  8725.                      comTerm.bStop        = comTemp.bStop;
  8726.                      comTerm.fWrap        = comTemp.fWrap;
  8727.                      comTerm.fHardware        = comTemp.fHardware;
  8728.                      comTerm.fSoftware        = comTemp.fSoftware;
  8729.                      if (COMMANDMSG(&msg)->cmd == IDD_SAVE) WriteOpts();
  8730.                  case DID_CANCEL: WinDismissDlg(hDlg, FALSE);
  8731.                  default: break;
  8732.              }
  8733.              break;
  8734.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  8735.      }
  8736.      return FALSE;
  8737.  }
  8738.  
  8739.  void Initialize(HWND hWnd) {
  8740.      ReadOpts(hWnd);
  8741.      fPaging = FALSE;
  8742.  }
  8743.  
  8744.  void ChangeSystemMenu(HWND hWnd) {
  8745.  /*
  8746.      Insert items into the System Menu (with thanks to Charles Petzold)
  8747.  */
  8748.      static CHAR *x[2] = { NULL, "~About ComTalk..." }; /* Items to add */
  8749.      static MENUITEM mi[2] = {        /* The RESOURCE definitions */
  8750.          MIT_END, MIS_SEPARATOR, 0x0000, 0, NULL, 0,
  8751.          MIT_END, MIS_TEXT, 0x0000, IDM_ABOUT, NULL, 0
  8752.      };
  8753.      HWND        hSM, hSSM;        /* Menu and submenu handles */
  8754.      MENUITEM        miSM;                /* System Menu Menuitem     */
  8755.      SHORT        idSM;                /* ID of the System Menu    */
  8756.      /*
  8757.          Get ahold of the system menu
  8758.      */
  8759.      hSM = WinWindowFromID(Parent(hWnd), FID_SYSMENU);
  8760.      idSM = SHORT1FROMMR( WinSendMsg(hSM, MM_ITEMIDFROMPOSITION, NULL, NULL));
  8761.      WinSendMsg(hSM, MM_QUERYITEM, MPFROM2SHORT(idSM, FALSE), MPFROMP(&miSM));
  8762.      /*
  8763.          Manipulate the System SubMenu
  8764.      */
  8765.      hSSM = miSM.hwndSubMenu;
  8766.      WinSendMsg(hSSM, MM_INSERTITEM, MPFROMP(mi), MPFROMP(x[0]));
  8767.      WinSendMsg(hSSM, MM_INSERTITEM, MPFROMP(mi+1), MPFROMP(x[1]));
  8768.  }
  8769.  
  8770.  MRESULT CALLBACK NewFrameWndProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp
  8771.  /*
  8772.      Force the frame to stay small enough
  8773.  */
  8774.      BOOL rc;                /* Return code for WM_QueryTrackInfo */
  8775.  
  8776.      switch(msg) {
  8777.          case WM_ADJUSTWINDOWPOS:        /* Calculate, then show scrollbars */
  8778.              AvioAdjustFrame(mp1);
  8779.              break;
  8780.          case WM_QUERYTRACKINFO:
  8781.              rc = (BOOL)SHORT1FROMMR ((*pfnOldFrameWndProc)(hWnd, msg, mp1, mp
  8782.              AvioQueryTrackInfo((PTRACKINFO) mp2);
  8783.              return (MRESULT) rc;
  8784.          default: break;
  8785.      }
  8786.      return (*pfnOldFrameWndProc)(hWnd, msg, mp1, mp2);
  8787.  }
  8788.  
  8789.  BOOL Filter(USHORT fs, char ch, USHORT vkey) {
  8790.      BOOL rc = FALSE;
  8791.  
  8792.      if (fs & KC_VIRTUALKEY) {
  8793.          switch(vkey) {
  8794.              case VK_HOME:
  8795.                  if (fs & KC_CTRL) rc = ThdPutString("\033[2J",4);
  8796.                  return (rc || ThdPutString("\033[H", 3));
  8797.              case VK_UP:
  8798.                  return ThdPutString("\033[A", 3);
  8799.              case VK_DOWN:
  8800.                  return ThdPutString("\033[B", 3);
  8801.              case VK_RIGHT:
  8802.                  return ThdPutString("\033[C", 3);
  8803.              case VK_LEFT:
  8804.                  return ThdPutString("\033[D", 3);
  8805.              default: break;
  8806.          }
  8807.      }
  8808.  
  8809.      if (fs & KC_CTRL) {
  8810.          switch (ch) {
  8811.              case 'l':
  8812.              case 'L': AvioRedraw();
  8813.              case '\0': return FALSE; break;
  8814.              default: ch = Ctrl(ch); break;
  8815.          }
  8816.      } else {
  8817.          switch (ch) {
  8818.              case '\0': return FALSE; break;
  8819.              default: break;
  8820.          }
  8821.      }
  8822.      return(rc || ThdPutChar(ch));
  8823.  }
  8824.  
  8825.  
  8826.  CPGREP.C
  8827.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CPGREP\CPGREP.C
  8828.  
  8829.  /* cpgrep - string searches
  8830.   *
  8831.   * Created by Microsoft Corp. 1986
  8832.   *
  8833.   *
  8834.   */
  8835.  
  8836.  #include                <os2def.h>
  8837.  #define INCL_DOSPROCESS
  8838.  #define INCL_DOSSEMAPHORES
  8839.  #define INCL_DOSQUEUES
  8840.  #define INCL_DOSMEMMGR
  8841.  #define INCL_DOSMISC
  8842.  #include                <bsedos.h>
  8843.  #include                <stdio.h>
  8844.  #include                <fcntl.h>
  8845.  #include                <ctype.h>
  8846.  
  8847.  #define        BEGLINE                0x40
  8848.  #define        DEBUG                0x08
  8849.  #define        ENDLINE                0x80
  8850.  #define        FILBUFLEN        (SECTORLEN*30)
  8851.  #define        FILNAMLEN        80
  8852.  #define        INVERT                0x10
  8853.  #define        ISCOT                0x0002
  8854.  #define        LG2SECLEN        9
  8855.  #define        LINELEN                128
  8856.  #define        LINENOS                0x04
  8857.  #define        LNOLEN                8
  8858.  #define        MAXSTRLEN        128
  8859.  #define        NAMEONLY        0x02
  8860.  #define        OUTBUFLEN        (SECTORLEN*4)
  8861.  #define        SECTORLEN        (1 << LG2SECLEN)
  8862.  #define        SHOWNAME        0x01
  8863.  #define        STKLEN                256
  8864.  #define        TIMER                0x20
  8865.  #define        TRTABLEN        256
  8866.  #define        s_text(x)        (((char *)(x)) - ((x)->s_must))
  8867.  
  8868.  typedef struct stringnode
  8869.    {
  8870.      struct stringnode        *s_alt;                /* List of alternates */
  8871.      struct stringnode        *s_suf;                /* List of suffixes */
  8872.      int                        s_must;                /* Length of portion th
  8873.    }
  8874.                          STRINGNODE;
  8875.  
  8876.  char                        filbuf[(FILBUFLEN + 2)*2];
  8877.  char                        *bufptr[] = { filbuf, filbuf + FILBUFLEN + 2 };
  8878.  char                        outbuf[OUTBUFLEN*2];
  8879.  char                        *obuf[] = { outbuf, outbuf + OUTBUFLEN };
  8880.  char                        *optr[] = { outbuf, outbuf + OUTBUFLEN };
  8881.  USHORT                        ocnt[] = { OUTBUFLEN, OUTBUFLEN };
  8882.  int                        oi = 0;
  8883.  char                        transtab[TRTABLEN] = { 0 };
  8884.  STRINGNODE                *stringlist[TRTABLEN/2];
  8885.  USHORT                        arrc;                /* I/O return code for Dos
  8886.  USHORT                        awrc;                /* I/O return code for Dos
  8887.  int                        casesen = 1;        /* Assume case-sensitivity */
  8888.  USHORT                        cbread;         /* Bytes read by DosRead */
  8889.  USHORT                        cbwrite;        /* Bytes written by DosWrite */
  8890.  int                        clists = 1;        /* One is first available index
  8891.  int                        flags;                /* Flags */
  8892.  int                        lineno;                /* Current line number */
  8893.  char                        pmode;                /* Protected mode flag */
  8894.  LONG                        readdone;        /* Async read done semaphore */
  8895.  LONG                        readpending;        /* Async read pending semapho
  8896.  int                        status = 1;        /* Assume failure */
  8897.  char                        *t2buf;                /* Async read buffer */
  8898.  USHORT                        t2buflen;        /* Async read buffer length */
  8899.  HFILE                        t2fd;                /* Async read file */
  8900.  char                        *t3buf;                /* Async write buffer */
  8901.  USHORT                        t3buflen;        /* Async write buffer length *
  8902.  HFILE                        t3fd;                /* Async write file */
  8903.  LONG                        writedone;        /* Async write done semaphore *
  8904.  LONG                        writepending;        /* Async write pending semap
  8905.  char                        target[MAXSTRLEN];
  8906.                                          /* Last string added */
  8907.  int                        targetlen;        /* Length of last string added *
  8908.  
  8909.  int                        countlines();        /* See CPGREPSB.ASM */
  8910.  int                        countmatched();        /* See CPGREPSB.ASM */
  8911.  char                        *findlist();        /* See CPGREPSB.ASM */
  8912.  char                        *findone();        /* See CPGREPSB.ASM */
  8913.  void                        flush1buf();        /* See below */
  8914.  int                        grepbuffer();        /* See below */
  8915.  int                        revfind();        /* See CPGREPSB.ASM */
  8916.  void                        write1buf();        /* See below */
  8917.  char                        *(*find)() = findlist;
  8918.  void                        (*flush1)() = flush1buf;
  8919.  int                        (*grep)() = grepbuffer;
  8920.  void                        (*write1)() = write1buf;
  8921.  
  8922.  void                        freenode(x)
  8923.  register STRINGNODE        *x;                /* Pointer to node to free */
  8924.    {
  8925.      register STRINGNODE        *y;                /* Pointer to next node in
  8926.  
  8927.      while(x != NULL)                        /* While not at end of list */
  8928.        {
  8929.          if(x->s_suf != NULL) freenode(x->s_suf);
  8930.                                          /* Free suffix list */
  8931.          y = x;                                /* Save pointer */
  8932.          x = x->s_alt;                        /* Move down the list */
  8933.          free(y);                        /* Free the node */
  8934.        }
  8935.    }
  8936.  
  8937.  
  8938.  STRINGNODE                *newnode(s,n)
  8939.  char                        *s;                /* String */
  8940.  int                        n;                /* Length of string */
  8941.    {
  8942.      register STRINGNODE        *new;                /* Pointer to new node */
  8943.      char                *t;                /* String pointer */
  8944.      char                *malloc();        /* Storage allocator */
  8945.  
  8946.      if((t = malloc(sizeof(STRINGNODE) + n + (n & 1))) == NULL)
  8947.        {                                        /* If allocation fails */
  8948.          fprintf(stderr,"Out of memory\n");
  8949.          DosExit( EXIT_PROCESS, 2);        /* Print error message and die */
  8950.        }
  8951.      if(n & 1) ++t;                        /* END of string word-aligned */
  8952.      strncpy(t,s,n);                        /* Copy string text */
  8953.      new = (STRINGNODE *)(t + n);        /* Set pointer to node */
  8954.      new->s_alt = NULL;                        /* No alternates yet */
  8955.      new->s_suf = NULL;                        /* No suffixes yet */
  8956.      new->s_must = n;                        /* Set string length */
  8957.      return(new);                        /* Return pointer to new node */
  8958.    }
  8959.  
  8960.  
  8961.  void                        reallocnode(node,s,n)
  8962.  register STRINGNODE        *node;                /* Pointer to node */
  8963.  char                        *s;                /* String */
  8964.  register int                n;                /* Length of string */
  8965.    {
  8966.      if(n > node->s_must)                /* If node must grow */
  8967.        {
  8968.          fprintf(stderr,"Internal error\n");
  8969.                                          /* Error message */
  8970.          DosExit( EXIT_PROCESS, 2);                          /* Error exit */
  8971.        }
  8972.      node->s_must = n;                        /* Set new length */
  8973.      memcpy(s_text(node),s,n);                /* Copy new text */
  8974.    }
  8975.  
  8976.  
  8977.  void                        addstring(s,n)
  8978.  char                        *s;                /* String to add */
  8979.  int                        n;                /* Length of string */
  8980.    {
  8981.      register STRINGNODE        *cur;                /* Current string */
  8982.      register STRINGNODE        **pprev;        /* Pointer to previous link */
  8983.      STRINGNODE                *new;                /* New string */
  8984.      int                        i;                /* Index */
  8985.      int                        j;                /* Count */
  8986.      int                        k;                /* Count */
  8987.  
  8988.      if(n <= 0 || n > 127) return;        /* Should never happen */
  8989.      i = transtab[*s];                        /* Get current index */
  8990.      if(i == 0)                                /* If no existing list */
  8991.        {
  8992.          /*
  8993.           *  We have to start a new list
  8994.           */
  8995.          if((i = clists++) >= TRTABLEN/2)
  8996.            {                                /* If too many string lists */
  8997.              fprintf(stderr,"Too many string lists\n");
  8998.                                          /* Error message */
  8999.              DosExit( EXIT_PROCESS, 2);        /* Die */
  9000.            }
  9001.          stringlist[i] = NULL;                /* Initialize */
  9002.          transtab[*s] = i;                /* Set pointer to new list */
  9003.          if(!casesen && isalpha(*s)) transtab[*s ^ '\x20'] = i;
  9004.                                          /* Set pointer for other case */
  9005.        }
  9006.      else if(stringlist[i] == NULL) return;
  9007.                                          /* Check for existing 1-byte string *
  9008.      if(--n == 0)                        /* If 1-byte string */
  9009.        {
  9010.          freenode(stringlist[i]);        /* Free any existing stuff */
  9011.          stringlist[i] = NULL;                /* No record here */
  9012.          return;                                /* Done */
  9013.        }
  9014.      ++s;                                /* Skip first char */
  9015.      pprev = stringlist + i;                /* Get pointer to link */
  9016.      cur = *pprev;                        /* Get pointer to node */
  9017.      while(cur != NULL)                        /* Loop to traverse match tree
  9018.        {
  9019.          i = (n > cur->s_must)? cur->s_must: n;
  9020.                                          /* Find minimum of string lengths */
  9021.          matchstrings(s,s_text(cur),i,&j,&k);
  9022.                                          /* Compare the strings */
  9023.          if(j == 0)                        /* If complete mismatch */
  9024.            {
  9025.              if(k < 0) break;                /* Break if insertion point found
  9026.              pprev = &(cur->s_alt);        /* Get pointer to alternate link */
  9027.              cur = *pprev;                /* Follow the link */
  9028.            }
  9029.          else if(i == j)                        /* Else if strings matched */
  9030.            {
  9031.              if(i == n)                        /* If new is prefix of current
  9032.                {
  9033.                  reallocnode(cur,s_text(cur),n);
  9034.                                          /* Shorten text of node */
  9035.                  if(cur->s_suf != NULL)        /* If there are suffixes */
  9036.                    {
  9037.                      freenode(cur->s_suf);
  9038.                                          /* Suffixes no longer needed */
  9039.                      cur->s_suf = NULL;
  9040.                    }
  9041.                  return;                        /* All done */
  9042.                }
  9043.              pprev = &(cur->s_suf);        /* Get pointer to suffix link */
  9044.              if((cur = *pprev) == NULL) return;
  9045.                                          /* Done if current is prefix of new *
  9046.              s += i;                        /* Skip matched portion */
  9047.              n -= i;
  9048.            }
  9049.          else                                /* Else partial match */
  9050.            {
  9051.              /*
  9052.               *        We must split an existing node.
  9053.               *        This is the trickiest case.
  9054.               */
  9055.              new = newnode(s_text(cur) + j,cur->s_must - j);
  9056.                                          /* Unmatched part of current string *
  9057.              reallocnode(cur,s_text(cur),j);
  9058.                                          /* Set length to matched portion */
  9059.              new->s_suf = cur->s_suf;        /* Current string's suffixes */
  9060.              if(k < 0)                        /* If new preceded current */
  9061.                {
  9062.                  cur->s_suf = newnode(s + j,n - j);
  9063.                                          /* FIrst suffix is new string */
  9064.                  cur->s_suf->s_alt = new;/* Alternate is part of current */
  9065.                }
  9066.              else                        /* Else new followed current */
  9067.                {
  9068.                  new->s_alt = newnode(s + j,n - j);
  9069.                                          /* Unmatched new string is alternate
  9070.                  cur->s_suf = new;        /* New suffix list */
  9071.                }
  9072.              return;
  9073.            }
  9074.        }
  9075.      *pprev = newnode(s,n);                /* Set pointer to new node */
  9076.      (*pprev)->s_alt = cur;                /* Attach alternates */
  9077.    }
  9078.  
  9079.  
  9080.  int                        addfancy(buffer,buflen,seplist)
  9081.  register char                *buffer;        /* Buffer */
  9082.  int                        buflen;                /* Length of buffer */
  9083.  char                        *seplist;        /* List of separators */
  9084.    {
  9085.      register char        *bufend;        /* Pointer to end of buffer */
  9086.      int                        strcnt = 0;        /* String count */
  9087.      int                        len;                /* String length */
  9088.      char                c;                /* One char buffer */
  9089.  
  9090.      bufend = buffer + buflen;                /* Set end pointer */
  9091.      while(buffer < bufend)                /* Loop through all strings */
  9092.        {
  9093.          len = strncspn(buffer,seplist,bufend - buffer);
  9094.                                          /* Length of string */
  9095.          if(flags & ENDLINE)                /* If match must be at end of line
  9096.            {
  9097.              c = buffer[len];                /* Save 1st character past string
  9098.              buffer[len++] = '\r';        /* Carriage return marks end of line
  9099.            }
  9100.          if(findlist(buffer,buffer + len) == NULL)
  9101.            {                                /* If no match within string */
  9102.              addstring(buffer,len);        /* Add string to list */
  9103.              if(strcnt++ == 0)                /* If first string */
  9104.                {
  9105.                  memcpy(target,buffer,len);
  9106.                                          /* Save first string in buffer */
  9107.                  targetlen = len;        /* Remember length */
  9108.                }
  9109.            }
  9110.          buffer += len;                        /* Skip over string */
  9111.          if(flags & ENDLINE) (--buffer)[0] = c;
  9112.                                          /* Restore saved character */
  9113.          buffer += strnspn(buffer,seplist,bufend - buffer);
  9114.                                          /* Skip over trailing separators */
  9115.        }
  9116.      return(strcnt);                        /* Return string count */
  9117.    }
  9118.  
  9119.  
  9120.  int                        addplain(buffer,buflen,seplist)
  9121.  register char                *buffer;        /* String list buffer */
  9122.  int                        buflen;                /* Buffer length */
  9123.  char                        *seplist;        /* List of separators */
  9124.    {
  9125.      int                        strcnt;                /* String count */
  9126.      register int        len;                /* String length */
  9127.      char                c;                /* One char buffer */
  9128.  
  9129.      strcnt = 0;
  9130.      while((len = strncspn(buffer,seplist,buflen)) > 0)
  9131.        {                                        /* While not at end of input l
  9132.          if(flags & ENDLINE)                /* If match must be at end of line
  9133.            {
  9134.              c = buffer[len];                /* Save 1st character past string
  9135.              buffer[len++] = '\r';        /* Carriage return marks end of line
  9136.            }
  9137.          if(strcnt == 0)                        /* Save first string */
  9138.            {
  9139.              strncpy(target,buffer,len);        /* Save string in buffer */
  9140.              targetlen = len;                /* Save string length */
  9141.            }
  9142.          addstring(buffer,len);                /* Add the string to the table
  9143.          if(flags & ENDLINE) buffer[--len] = c;
  9144.                                          /* Restore saved character */
  9145.          buffer += len;                        /* Skip the string */
  9146.          buflen -= len;
  9147.          len = strnspn(buffer,seplist,buflen);
  9148.                                          /* Skip separators */
  9149.          buffer += len;
  9150.          buflen -= len;
  9151.          ++strcnt;                        /* Increment string count */
  9152.        }
  9153.      return(strcnt);                        /* Return string count */
  9154.    }
  9155.  
  9156.  
  9157.  void                        dumplist(node,indent)
  9158.  register STRINGNODE        *node;                /* Pointer to list to dump *
  9159.  int                        indent;                /* Current length of buffer
  9160.    {
  9161.      int                        i;                /* Counter */
  9162.  
  9163.      while(node != NULL)                        /* While not at end of list */
  9164.        {
  9165.          for(i = 0; i < indent; ++i) fputc(' ',stderr);
  9166.          fwrite(s_text(node),sizeof(char),node->s_must,stderr);
  9167.          fprintf(stderr,"\n");
  9168.          if(node->s_suf != NULL)
  9169.            dumplist(node->s_suf,indent + node->s_must);
  9170.                                          /* Recurse to do suffixes */
  9171.          node = node->s_alt;                /* Do next alternate in list */
  9172.        }
  9173.    }
  9174.  
  9175.  
  9176.  void                        dumpstrings()
  9177.    {
  9178.      int                        i;                /* Index */
  9179.  
  9180.      for(i = 0; i < TRTABLEN; ++i)        /* Loop through translation table */
  9181.        {
  9182.          if(transtab[i] == 0) continue;        /* Skip null entries */
  9183.          fprintf(stderr,"%c\n",i);        /* Print the first byte */
  9184.          dumplist(stringlist[transtab[i]],1);
  9185.                                          /* Dump the list */
  9186.        }
  9187.    }
  9188.  
  9189.  
  9190.  HFILE                        openfile(name)
  9191.  char                        *name;                /* File name */
  9192.    {
  9193.      HFILE                fd;                /* File descriptor */
  9194.  
  9195.      if((fd = open(name,0)) == -1)        /* If error opening file */
  9196.        {
  9197.          fprintf(stderr,"Cannot open %s\r\n",name);
  9198.                                          /* Print error message */
  9199.        }
  9200.      return(fd);                                /* Return file descriptor */
  9201.    }
  9202.  
  9203.  
  9204.  void far                thread2()        /* Read thread */
  9205.    {
  9206.      while(DosSemRequest( &readpending, -1L) == 0)
  9207.        {                                        /* While there is work to do *
  9208.          arrc = DosRead( t2fd, t2buf, t2buflen, &cbread);
  9209.                                          /* Do the read */
  9210.          DosSemClear( &readdone);        /* Signal read completed */
  9211.        }
  9212.      fprintf(stderr,"Thread 2: DosSemRequest failed\n");
  9213.                                          /* Print error message */
  9214.      DosExit( EXIT_PROCESS, 2);                /* Die */
  9215.    }
  9216.  
  9217.  
  9218.  void far                thread3()        /* Write thread */
  9219.    {
  9220.      while(DosSemRequest((long far *) &writepending,-1L) == 0)
  9221.        {                                        /* While there is work to do *
  9222.          awrc = DosWrite(t3fd, t3buf, t3buflen, &cbwrite);
  9223.                                          /* Do the write */
  9224.          DosSemClear( &writedone);        /* Signal write completed */
  9225.        }
  9226.      fprintf(stderr,"Thread 3: DosSemRequest failed\n");
  9227.                                          /* Print error message */
  9228.      DosExit( EXIT_PROCESS, 2);                /* Die */
  9229.    }
  9230.  
  9231.  
  9232.  void                        startread(fd,buffer,buflen)
  9233.  HFILE                        fd;                /* File handle */
  9234.  char                        *buffer;        /* Buffer */
  9235.  USHORT                        buflen;         /* Buffer length */
  9236.    {
  9237.      if(pmode)                                /* If protected mode */
  9238.        {
  9239.          if(DosSemRequest( &readdone, -1L) != 0)
  9240.            {                                /* If we fail to get the semaphore
  9241.              fprintf(stderr,"DosSemRequest failed\n");
  9242.                                          /* Error message */
  9243.              DosExit( EXIT_PROCESS, 2);        /* Die */
  9244.            }
  9245.          t2fd = fd;                        /* Set parameters for read */
  9246.          t2buf = buffer;
  9247.          t2buflen = buflen;
  9248.          DosSemClear( &readpending);        /* Wake thread 2 for read */
  9249.          DosSleep(0L);                        /* Yield the CPU */
  9250.        }
  9251.      else arrc = DosRead( fd, buffer, buflen, &cbread);
  9252.    }
  9253.  
  9254.  
  9255.  int                        finishread()
  9256.    {
  9257.      if(pmode && DosSemWait( &readdone, -1L) != 0)
  9258.        {                                        /* If protected mode and wait
  9259.          fprintf(stderr,"DosSemWait failed\n");
  9260.                                          /* Print error message */
  9261.          DosExit( EXIT_PROCESS, 2);                          /* Die */
  9262.        }
  9263.      return((arrc == 0)? cbread: -1);        /* Return number of bytes read */
  9264.    }
  9265.  
  9266.  
  9267.  void                        startwrite(fd,buffer,buflen)
  9268.  HFILE                        fd;                /* File handle */
  9269.  char                        *buffer;        /* Buffer */
  9270.  USHORT                        buflen;         /* Buffer length */
  9271.    {
  9272.      if(pmode)                                /* If protected mode */
  9273.        {
  9274.          if(DosSemRequest( &writedone, -1L) != 0)
  9275.            {                                /* If we fail to get the semaphore
  9276.              fprintf(stderr,"DosSemRequest failed\n");
  9277.                                          /* Error message */
  9278.              DosExit( EXIT_PROCESS, 2);        /* Die */
  9279.            }
  9280.          t3fd = fd;                        /* Set parameters for write */
  9281.          t3buf = buffer;
  9282.          t3buflen = buflen;
  9283.          DosSemClear( &writepending);        /* Wake thread 3 for read */
  9284.          DosSleep(0L);                        /* Yield the CPU */
  9285.        }
  9286.      else awrc = DosWrite(fd, buffer, buflen, &cbwrite);
  9287.    }
  9288.  
  9289.  
  9290.  int                        finishwrite()
  9291.    {
  9292.      if(pmode && DosSemWait( &writedone, -1L) != 0)
  9293.        {                                        /* If protected mode and wait
  9294.          fprintf(stderr,"DosSemWait failed\n");
  9295.                                          /* Print error message */
  9296.          DosExit( EXIT_PROCESS, 2);        /* Die */
  9297.        }
  9298.      return((awrc == 0)? cbwrite: -1);        /* Return number of bytes writte
  9299.    }
  9300.  
  9301.  
  9302.  void                        write1nobuf(buffer,buflen)
  9303.  char                        *buffer;        /* Buffer */
  9304.  USHORT                        buflen;         /* Buffer length */
  9305.    {
  9306.      int                        cb;                /* Count of bytes written *
  9307.  
  9308.      if( DosWrite(1, buffer, buflen, &cb) != 0 || cb != buflen)
  9309.                                          /* If write fails */
  9310.        {
  9311.          fprintf(stderr,"write error %d\n",awrc);
  9312.                                          /* Print error message */
  9313.          DosExit( EXIT_PROCESS, 2);        /* Die */
  9314.        }
  9315.    }
  9316.  
  9317.  
  9318.  void                        write1buf(buffer,buflen)
  9319.  char                        *buffer;        /* Buffer */
  9320.  USHORT                        buflen;         /* Buffer length */
  9321.    {
  9322.      USHORT                cb;                /* Byte count */
  9323.  
  9324.      while(buflen > 0)                        /* While bytes remain */
  9325.        {
  9326.          if(awrc != 0)                        /* If previous write failed */
  9327.            {
  9328.              fprintf(stderr,"write error %d\n",awrc);
  9329.                                          /* Print error message */
  9330.              DosExit( EXIT_PROCESS, 2);                          /* Die */
  9331.            }
  9332.          if((cb = ocnt[oi]) == 0)        /* If buffer full */
  9333.            {
  9334.              startwrite(1,obuf[oi],OUTBUFLEN);
  9335.                                          /* Write the buffer */
  9336.              ocnt[oi] = OUTBUFLEN;        /* Reset count and pointer */
  9337.              optr[oi] = obuf[oi];
  9338.              oi ^= 1;                        /* Switch buffers */
  9339.              cb = ocnt[oi];                /* Get space remaining */
  9340.            }
  9341.          if(cb > buflen) cb = buflen;        /* Get minimum */
  9342.          memcpy(optr[oi],buffer,cb);        /* Copy bytes to buffer */
  9343.          ocnt[oi] -= cb;                        /* Update buffer length and po
  9344.          optr[oi] += cb;
  9345.          buflen -= cb;
  9346.          buffer += cb;
  9347.        }
  9348.    }
  9349.  
  9350.  
  9351.  void                        flush1nobuf()
  9352.    {
  9353.    }
  9354.  
  9355.  
  9356.  void                        flush1buf()
  9357.    {
  9358.      int                        cb;                /* Byte count */
  9359.  
  9360.      if((cb = OUTBUFLEN - ocnt[oi]) > 0)        /* If buffer not empty */
  9361.        {
  9362.          startwrite(1,obuf[oi],cb);        /* Start write */
  9363.          if(finishwrite() != cb)                /* If write failed */
  9364.            {
  9365.              fprintf(stderr,"write error %d\n",awrc);
  9366.                                          /* Print error message */
  9367.              DosExit( EXIT_PROCESS, 2);        /* Die */
  9368.            }
  9369.        }
  9370.    }
  9371.  
  9372.  
  9373.  int                        grepnull(cp,endbuf,name)
  9374.  register char                *cp;                /* Buffer pointer */
  9375.  char                        *endbuf;        /* End of buffer */
  9376.  char                        *name;                /* File name */
  9377.    {
  9378.      return(0);                                /* Do nothing */
  9379.    }
  9380.  
  9381.  
  9382.  int                        grepbuffer(startbuf,endbuf,name)
  9383.  char                        *startbuf;        /* Start of buffer */
  9384.  char                        *endbuf;        /* End of buffer */
  9385.  char                        *name;                /* File name */
  9386.    {
  9387.      register char        *cp;                /* Buffer pointer */
  9388.      char                *lastmatch;        /* Last matching line */
  9389.      int                        linelen;        /* Line length */
  9390.      int                        namlen = 0;        /* Length of name */
  9391.      char                lnobuf[LNOLEN];        /* Line number buffer */
  9392.      char                nambuf[LINELEN];/* Name buffer */
  9393.  
  9394.      cp = startbuf;                        /* Initialize to start of buffer */
  9395.      lastmatch = cp;                        /* No previous match yet */
  9396.      while((cp = (*find)(cp,endbuf)) != NULL)
  9397.        {                                        /* While matches are found */
  9398.          if((flags & BEGLINE) && cp[-1] != '\n' && cp > startbuf)
  9399.            {                                /* If begin line conditions not me
  9400.              ++cp;                        /* Skip first char of match */
  9401.              continue;                        /* Keep looking */
  9402.            }
  9403.          status = 0;                        /* Match found */
  9404.          if(flags & NAMEONLY)                /* If filename only wanted */
  9405.            {
  9406.              (*write1)(nambuf,sprintf(nambuf,"%s\r\n",name));
  9407.                                          /* Print the name */
  9408.              return(1);                        /* Punt remainder of buffer */
  9409.            }
  9410.          cp -= revfind(cp,'\n',cp - startbuf);
  9411.                                          /* Point at last linefeed */
  9412.          if(*cp == '\n') ++cp;                /* Point at start of line */
  9413.          if(flags & SHOWNAME)                /* If name wanted */
  9414.            {
  9415.              if(namlen == 0) namlen = sprintf(nambuf,"%s:",name);
  9416.                                          /* Format name if not done already */
  9417.              (*write1)(nambuf,namlen);        /* Show name */
  9418.            }
  9419.          if(flags & LINENOS)                /* If line number wanted */
  9420.            {
  9421.              lineno += countlines(lastmatch,cp);
  9422.                                          /* Count lines since last match */
  9423.              (*write1)(lnobuf,sprintf(lnobuf,"%d:",lineno));
  9424.                                          /* Print line number */
  9425.              lastmatch = cp;                /* New last match */
  9426.            }
  9427.          linelen = strncspn(cp,"\n",endbuf - cp) + 1;
  9428.                                          /* Calculate line length */
  9429.          (*write1)(cp,linelen);                /* Print the line */
  9430.          cp += linelen;                        /* Skip the line */
  9431.        }
  9432.      if(flags & LINENOS) lineno += countlines(lastmatch,endbuf);
  9433.                                          /* Count remaining lines in buffer */
  9434.      return(0);                                /* Keep searching */
  9435.    }
  9436.  
  9437.  
  9438.  void                        showv(name,lastmatch,thismatch)
  9439.  char                        *name;
  9440.  register char                *lastmatch;
  9441.  char                        *thismatch;
  9442.    {
  9443.      register int        linelen;
  9444.      int                        namlen = 0;        /* Length of name */
  9445.      char                lnobuf[LNOLEN];        /* Line number buffer */
  9446.      char                nambuf[LINELEN];/* Name buffer */
  9447.  
  9448.      if(flags & (SHOWNAME | LINENOS))
  9449.        {
  9450.          while(lastmatch < thismatch)
  9451.            {
  9452.              if(flags & SHOWNAME)        /* If name wanted */
  9453.                {
  9454.                  if(namlen == 0) namlen = sprintf(nambuf,"%s:",name);
  9455.                                          /* Format name if not done already */
  9456.                  (*write1)(nambuf,namlen);
  9457.                                          /* Write the name */
  9458.                }
  9459.              if(flags & LINENOS)
  9460.                {
  9461.                  (*write1)(lnobuf,sprintf(lnobuf,"%d:",lineno++));
  9462.                }
  9463.              linelen = strncspn(lastmatch,"\n",thismatch - lastmatch) + 1;
  9464.              (*write1)(lastmatch,linelen);
  9465.              lastmatch += linelen;
  9466.            }
  9467.        }
  9468.      else (*write1)(lastmatch,thismatch - lastmatch);
  9469.    }
  9470.  
  9471.  
  9472.  int                        grepvbuffer(startbuf,endbuf,name)
  9473.  char                        *startbuf;        /* Start of buffer */
  9474.  char                        *endbuf;        /* End of buffer */
  9475.  char                        *name;                /* File name */
  9476.    {
  9477.      register char        *cp;                /* Buffer pointer */
  9478.      register char        *lastmatch;        /* Pointer to line after last mat
  9479.  
  9480.      cp = startbuf;                        /* Initialize to start of buffer */
  9481.      lastmatch = cp;
  9482.      while((cp = (*find)(cp,endbuf)) != NULL)
  9483.        {
  9484.          if((flags & BEGLINE) && cp[-1] != '\n' && cp > startbuf)
  9485.            {                                /* If begin line conditions not me
  9486.              ++cp;                        /* Skip first char of match */
  9487.              continue;                        /* Keep looking */
  9488.            }
  9489.          status = 1;                        /* Match found */
  9490.          if(flags & NAMEONLY) return(1);        /* Skip rest of file if NAMEON
  9491.          cp -= revfind(cp,'\n',cp - startbuf);
  9492.                                          /* Point at last linefeed */
  9493.          if(*cp == '\n') ++cp;                /* Point at start of line */
  9494.          showv(name,lastmatch,cp);        /* Show from last match to this */
  9495.          cp += strncspn(cp,"\n",endbuf - cp) + 1;
  9496.                                          /* Skip over line with match */
  9497.          lastmatch = cp;                        /* New "last" match */
  9498.          ++lineno;                        /* Increment line count */
  9499.        }
  9500.      if(!(flags & NAMEONLY)) showv(name,lastmatch,endbuf);
  9501.                                          /* Show buffer tail if not NAMEONLY *
  9502.      return(0);                                /* Keep searching file */
  9503.    }
  9504.  
  9505.  
  9506.  void                        qgrep(name,fd)
  9507.  char                        *name;                /* File name */
  9508.  HFILE                        fd;                /* File descriptor */
  9509.    {
  9510.      register int        cb;                /* Byte count */
  9511.      register char        *cp;                /* Buffer pointer */
  9512.      char                *endbuf;        /* End of buffer */
  9513.      int                        taillen;        /* Length of buffer tail */
  9514.      int                        bufi;                /* Buffer index */
  9515.      char                line[LINELEN];        /* Line buffer */
  9516.  
  9517.      lineno = 1;                                /* File starts on line 1 */
  9518.      taillen = 0;                        /* No buffer tail yet */
  9519.      bufi = 0;                                /* Initialize buffer index */
  9520.      cp = bufptr[0];                        /* Initialize to start of buffer *
  9521.      finishread();                        /* Make sure no I/O activity */
  9522.      arrc = DosRead( fd, cp, FILBUFLEN, &cbread);
  9523.                                          /* Do first read synchronously */
  9524.      while((cb = finishread()) + taillen > 0)
  9525.        {                                        /* While search incomplete */
  9526.          if(cb == 0)                        /* If buffer tail is all that's le
  9527.            {
  9528.              taillen = 0;                /* Set tail length to zero */
  9529.              *cp++ = '\r';                /* Add end of line sequence */
  9530.              *cp++ = '\n';
  9531.              endbuf = cp;                /* Note end of buffer */
  9532.            }
  9533.          else                                /* Else start next read */
  9534.            {
  9535.              taillen = revfind(cp + cb - 1,'\n',cb);
  9536.                                          /* Find length of partial line */
  9537.              endbuf = cp + cb - taillen;        /* Get pointer to end of buffe
  9538.              cp = bufptr[bufi ^ 1];        /* Pointer to other buffer */
  9539.              memcpy(cp,endbuf,taillen);        /* Copy tail to head of other b
  9540.              cp += taillen;                /* Skip over tail */
  9541.              startread(fd,cp,(FILBUFLEN - taillen) & (~0 << LG2SECLEN));
  9542.                                          /* Start next read */
  9543.            }
  9544.          if((*grep)(bufptr[bufi],endbuf,name)) return;
  9545.                                          /* Done if NAMEONLY and match found *
  9546.          bufi ^= 1;                        /* Switch buffers */
  9547.        }
  9548.      if((flags & (NAMEONLY | INVERT)) == (NAMEONLY | INVERT))
  9549.        (*write1)(line,sprintf(line,"%s\r\n",name));
  9550.                                          /* Write name if -lv */
  9551.    }
  9552.  
  9553.  
  9554.  void                        usage(verbose)
  9555.  int                        verbose;        /* Verbose message flag */
  9556.    {
  9557.      static char                *opts[] =
  9558.        {
  9559.          "-? - print this message",
  9560.          "-B - match pattern if at beginning of line",
  9561.          "-E - match pattern if at end of line",
  9562.          "-l - print only file name if file contains match",
  9563.          "-n - print line number before each matching line",
  9564.          "-v - print only lines not containing a match",
  9565.          "-x - print lines that match exactly (-BE)",
  9566.          "-y - treat upper and lower case as equivalent",
  9567.          "-e - treat next argument as the search string",
  9568.          "-f - read search strings from file named by next argument",
  9569.          "-i - read file list from file named by next argument",
  9570.          0
  9571.        };
  9572.      register char        **opt = opts;        /* Option list */
  9573.  
  9574.      fprintf(stderr,"usage: CPGREP [-?BElnvxy][-e][-f <file>][-i <file>][<stri
  9575.      if(verbose)                                /* If verbose message wanted *
  9576.        {
  9577.          while(*opt != 0) fprintf(stderr,"%s\n",*opt++);
  9578.                                          /* Print option list */
  9579.        }
  9580.      DosExit( EXIT_PROCESS, 2);                /* Error exit */
  9581.    }
  9582.  
  9583.  
  9584.  void                        main(argc,argv)
  9585.  int                        argc;
  9586.  char                        **argv;
  9587.    {
  9588.      register char        *cp;
  9589.      HFILE                fd;
  9590.      FILE                *fi;
  9591.      char                filnam[FILNAMLEN];
  9592.      USHORT                handType;
  9593.      USHORT                handAttrib;
  9594.      int                        i;
  9595.      char                *inpfile = NULL;
  9596.      int                 j;
  9597.      char                *seplist = " \t";
  9598.      int                        strcnt;
  9599.      char                *strfile = NULL;
  9600.      long                start;                /* Start time */
  9601.      int                        (*add)();
  9602.      BYTE                t2stk[2*STKLEN];  /* Read thread stack */
  9603.      BYTE                t3stk[2*STKLEN];  /* Write thread stack */
  9604.      long                time();                /* Time and date in seconds */
  9605.  
  9606.      DosGetMachineMode((char far *) &pmode);
  9607.      flags = 0;
  9608.      for(i = 1; i < argc && argv[i][0] == '-'; ++i)
  9609.        {
  9610.          switch(argv[i][1])
  9611.            {
  9612.              case 'f':
  9613.              case 'i':
  9614.                if(i == argc - 1)
  9615.                  {
  9616.                    fprintf(stderr,"File name missing after -%c\n",argv[i][1]);
  9617.                    DosExit( EXIT_PROCESS, 2);
  9618.                  }
  9619.                if(argv[i++][1] == 'i') inpfile = argv[i];
  9620.                else strfile = argv[i];
  9621.                break;
  9622.  
  9623.              case '?':
  9624.              case 'B':
  9625.              case 'E':
  9626.              case 'N':
  9627.              case 'S':
  9628.              case 'd':
  9629.              case 'l':
  9630.              case 'n':
  9631.              case 't':
  9632.              case 'v':
  9633.              case 'x':
  9634.              case 'y':
  9635.                for(cp = &argv[i][1]; *cp != '\0'; ++cp)
  9636.                  {
  9637.                    switch(*cp)
  9638.                      {
  9639.                        case '?':
  9640.                          usage(1);        /* Verbose usage message */
  9641.  
  9642.                        case 'B':
  9643.                          flags |= BEGLINE;
  9644.                          break;
  9645.  
  9646.                        case 'E':
  9647.                          flags |= ENDLINE;
  9648.                          break;
  9649.  
  9650.                        case 'N':
  9651.                          grep = grepnull;
  9652.                          break;
  9653.  
  9654.                        case 'S':
  9655.                          pmode = 0;        /* Force synchronous I/O */
  9656.                          break;
  9657.  
  9658.                        case 'd':
  9659.                          flags |= DEBUG;
  9660.                          break;
  9661.  
  9662.                        case 'l':
  9663.                          flags |= NAMEONLY;
  9664.                          break;
  9665.  
  9666.                        case 'n':
  9667.                          flags |= LINENOS;
  9668.                          break;
  9669.  
  9670.                        case 't':
  9671.                          flags |= TIMER;
  9672.                          break;
  9673.  
  9674.                        case 'v':
  9675.                          status = 0;        /* Assume success */
  9676.                          flags |= INVERT;
  9677.                          grep = grepvbuffer;
  9678.                          break;
  9679.  
  9680.                        case 'x':
  9681.                          flags |= BEGLINE | ENDLINE;
  9682.                          break;
  9683.  
  9684.                        case 'y':
  9685.                          casesen = 0;
  9686.                          break;
  9687.  
  9688.                        default:
  9689.                          fprintf(stderr,"-%c ignored\n",*cp);
  9690.                          break;
  9691.                      }
  9692.                  }
  9693.                break;
  9694.  
  9695.              case 'e':
  9696.                if(strfile == NULL)
  9697.                  {
  9698.                    ++i;
  9699.                    seplist = "";                /* Allow anything in string */
  9700.                    goto endfor0;
  9701.                  }
  9702.                /* Drop through to "default" */
  9703.  
  9704.              default:
  9705.                fprintf(stderr,"%s ignored\n",argv[i]);
  9706.                break;
  9707.            }
  9708.        }
  9709.      endfor0:
  9710.  
  9711.      if(i == argc && strfile == NULL) usage(0);
  9712.                                          /* Simple usage message if arg error
  9713.      if(flags & TIMER) start = time(NULL);
  9714.                                          /* Get start time if timer on */
  9715.      if(pmode)                                /* Initialize semaphores and thr
  9716.        {
  9717.          TID threadId;
  9718.  
  9719.          DosSemClear( &readdone);
  9720.          DosSemClear( &writedone);
  9721.          DosSemSet( &readpending);
  9722.          DosSemSet( &writepending);
  9723.          if(DosCreateThread(thread2, &threadId, t2stk + 2*STKLEN) != 0 ||
  9724.             DosCreateThread(thread3, &threadId, t3stk + 2*STKLEN) != 0)
  9725.            {                                /* If thread creation fails */
  9726.              fprintf(stderr,"Failed to create child threads\n");
  9727.                                          /* Print error message */
  9728.              DosExit( EXIT_PROCESS, 2);        /* Die */
  9729.            }
  9730.        }
  9731.      setmode(fileno(stdout),O_BINARY);
  9732.      add = addplain;                        /* Assume plain string adds */
  9733.      if(strfile != NULL)                        /* If strings from file */
  9734.        {
  9735.          if(!(flags & BEGLINE)) add = addfancy;
  9736.                                          /* Try to add intelligently */
  9737.          if((fd = open(strfile,0)) == -1)
  9738.            {                                /* If open fails */
  9739.              fprintf(stderr,"Cannot read strings from %s\n",strfile);
  9740.              DosExit( EXIT_PROCESS, 2);                          /* Print mess
  9741.            }
  9742.          for(cp = filbuf, j = 0; (j = read(fd,cp,FILBUFLEN*2 - j)) > 0; cp +=
  9743.                                          /* Read strings file into buffer */
  9744.          j = cp - filbuf;                /* Get total length of buffer */
  9745.          close(fd);                        /* Close strings file */
  9746.          filbuf[j] = '\0';                /* Null-terminate the buffer */
  9747.          cp = filbuf;                        /* Set pointer to string list */
  9748.          seplist = "\r\n";                /* Only '\r' and '\n' are separators
  9749.        }
  9750.      else                                /* Else strings on command line */
  9751.        {
  9752.          cp = argv[i++];                        /* Set pointer to strings */
  9753.          j = strlen(cp);                        /* Get length of strings */
  9754.        }
  9755.      if((strcnt = (*add)(cp,j,seplist)) == 0)
  9756.        {                                        /* If no strings */
  9757.          fprintf(stderr,"No search strings\n");
  9758.          DosExit( EXIT_PROCESS, 2);        /* Print error message and die */
  9759.        }
  9760.  
  9761.      /*
  9762.       *  Check type of handle for std. out.
  9763.       */
  9764.      if(DosQHandType(fileno(stdout), &handType, &handAttrib) != 0)
  9765.        {                                        /* If error */
  9766.          fprintf(stderr,"Standard output bad handle\n");
  9767.                                          /* Print error message */
  9768.          DosExit( EXIT_PROCESS, 2);        /* Die */
  9769.        }
  9770.      if(handType != 0 && (handAttrib & ISCOT))
  9771.        {                                 /* If handle is console output */
  9772.          write1 = write1nobuf;                /* Use unbuffered output */
  9773.          flush1 = flush1nobuf;
  9774.        }
  9775.  
  9776.      if(strcnt > 1)                        /* If more than one string */
  9777.        {
  9778.          if(flags & DEBUG)                /* Print debug info maybe */
  9779.            {
  9780.              fprintf(stderr,"Here are the strings:\n");
  9781.              dumpstrings();
  9782.            }
  9783.        }
  9784.      else if(casesen) find = findone;        /* Else use findone() */
  9785.      if(inpfile != NULL)                        /* If file list from file */
  9786.        {
  9787.          flags |= SHOWNAME;                /* Always show name of file */
  9788.          if((fi = fopen(inpfile,"r")) == NULL)
  9789.            {                                /* If open fails */
  9790.              fprintf(stderr,"Cannot read file list from %s\r\n",inpfile);
  9791.                                          /* Error message */
  9792.              DosExit( EXIT_PROCESS, 2);        /* Error exit */
  9793.            }
  9794.          while(fgets(filnam,FILNAMLEN,fi) != NULL)
  9795.            {                                /* While there are names */
  9796.              filnam[strcspn(filnam,"\r\n")] = '\0';
  9797.                                          /* Null-terminate the name */
  9798.              if((fd = openfile(filnam)) == -1) continue;
  9799.                                          /* Skip file if it cannot be opened *
  9800.              qgrep(filnam,fd);                /* Do the work */
  9801.              close(fd);                        /* Close the file */
  9802.            }
  9803.          fclose(fi);                        /* Close the list file */
  9804.        }
  9805.      else if(i == argc)
  9806.        {
  9807.          flags &= ~(NAMEONLY | SHOWNAME);
  9808.          setmode(fileno(stdin),O_BINARY);
  9809.          qgrep(NULL,fileno(stdin));
  9810.        }
  9811.      if(argc > i + 1) flags |= SHOWNAME;
  9812.      for(; i < argc; ++i)
  9813.        {
  9814.          if((fd = openfile(argv[i])) == -1) continue;
  9815.          qgrep(argv[i],fd);
  9816.          close(fd);
  9817.        }
  9818.      (*flush1)();
  9819.      if(flags & TIMER) fprintf(stderr,"%ld seconds\n",time(NULL) - start);
  9820.                                          /* Print elapsed time if timer on */
  9821.      DosExit( EXIT_PROCESS, status);
  9822.    }
  9823.  
  9824.  
  9825.  CPGREPSB.ASM
  9826.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CPGREP\CPGREPSB.ASM
  9827.  
  9828.  ; Created by Microsoft Corp. 1986
  9829.  name cpgrepsub
  9830.  
  9831.  retlen        equ        2                        ; Size of return address on
  9832.  
  9833.  dgroup        group        _data
  9834.  
  9835.  extrn        _casesen:        word                ; Case-sensitivity flag
  9836.  extrn        _stringlist:        word                ; Table of string lists
  9837.  extrn        _target:        byte                ; Target string
  9838.  extrn        _targetlen:        word                ; Length of target string
  9839.  extrn        _transtab:        byte                ; Translation table for _f
  9840.  
  9841.  ;        This segment is puposely word-aligned.  See note
  9842.  ;        in _findlist below.
  9843.  
  9844.  _text        segment word public 'code'
  9845.          assume        cs:_text, ds:dgroup, es:nothing, ss:dgroup
  9846.  
  9847.  ; char                        *findone(buffer,bufend)
  9848.  ; char                        *buffer                /* Buffer in which to se
  9849.  ; char                        *bufend;        /* End of buffer */
  9850.  ;
  9851.  ; NOTE: targetlen MUST BE greater than zero
  9852.  
  9853.  buffer        equ        word ptr [bp+retlen+2]
  9854.  bufend        equ        word ptr [bp+retlen+4]
  9855.  
  9856.          EVEN
  9857.  
  9858.          public        _findone
  9859.  _findone proc        near
  9860.          push        bp
  9861.          mov        bp,sp
  9862.          push        di
  9863.          push        si
  9864.          push        es
  9865.          push        ds                        ; ES = DS
  9866.          pop        es
  9867.          mov        cx,bufend                ; CX = end of buffer
  9868.          mov        di,buffer                ; ES:DI = buffer
  9869.          sub        cx,di                        ; CX = length of buffer
  9870.          jbe        sfnomatch                ;  length less than or equal to z
  9871.          mov        dx,_targetlen                ; DX = length of target
  9872.          dec        dx                        ; Decrement it
  9873.          sub        cx,dx                        ; target must fit in buffer
  9874.          jbe        sfnomatch                ;  (no match if buffer too short)
  9875.  
  9876.  ;        CX = buffer length
  9877.  ;        DX = target length (minus first character)
  9878.  ;        ES:DI = buffer pointer
  9879.  
  9880.  sf0:        jcxz        sfnomatch                ; No match if count zero
  9881.          mov        si,offset dgroup:_target ; DS:SI = target
  9882.          lodsb                                ; AL = first byte of target
  9883.          repne scasb                        ; Look for first character
  9884.          jne        sfnomatch                ;  jump if not found
  9885.          mov        bx,cx                        ; BX = buffer length
  9886.          mov        ax,di                        ; AX = buffer pointer
  9887.          mov        cx,dx                        ; Get count for cmpsb
  9888.          or        cx,cx                        ; Zero? (JCXZ doesn't set flag
  9889.          je        sf1                        ;  yes, skip compare
  9890.          repe cmpsb                        ; Do string compare
  9891.  sf1:        mov        di,ax                        ; DI = buffer pointer
  9892.          mov        cx,bx                        ; CX = buffer length
  9893.          jne        sf0                        ; Loop if no match
  9894.          dec        ax                        ; AX = offset of start of match
  9895.          jmp        short sf4
  9896.  
  9897.  sfnomatch:
  9898.          xor        ax,ax                        ; No match
  9899.  sf4:        pop        es
  9900.          pop        si
  9901.          pop        di
  9902.          pop        bp
  9903.          ret
  9904.  _findone endp
  9905.  
  9906.  
  9907.  ; int                        revfind(s,c,slen)
  9908.  ; char                        *s;                /* String to search */
  9909.  ; int                        c;                /* Char to search for */
  9910.  ; int                        slen;                /* Length of s */
  9911.  
  9912.  s        equ        [bp+retlen+2]
  9913.  c        equ        [bp+retlen+4]
  9914.  slen        equ        [bp+retlen+6]
  9915.  
  9916.          EVEN
  9917.  
  9918.          public        _revfind
  9919.  _revfind proc        near
  9920.          push        bp
  9921.          mov        bp,sp
  9922.          push        di
  9923.          push        es
  9924.          push        ds
  9925.          pop        es
  9926.          mov        di,s
  9927.          mov        ax,c
  9928.          mov        cx,slen
  9929.          jcxz        rf1
  9930.          std
  9931.          repne scasb
  9932.          cld
  9933.          mov        cx,s
  9934.          jne        rf0
  9935.          inc        di
  9936.  rf0:        sub        cx,di
  9937.  rf1:        mov        ax,cx
  9938.          pop        es
  9939.          pop        di
  9940.          pop        bp
  9941.          ret
  9942.  _revfind endp
  9943.  
  9944.  
  9945.  ; int                        countlines(start,finish)
  9946.  ; char                        *start;
  9947.  ; char                        *finish;
  9948.  
  9949.  start        equ        [bp+retlen+2]
  9950.  finish        equ        [bp+retlen+4]
  9951.  
  9952.          EVEN
  9953.  
  9954.          public        _countlines
  9955.  _countlines proc near
  9956.          push        bp
  9957.          mov        bp,sp
  9958.          push        di
  9959.          push        es
  9960.          push        ds
  9961.          pop        es
  9962.          xor        dx,dx                        ; Accumulate count in DX
  9963.          mov        di,start                ; ES:DI points to start
  9964.          mov        cx,finish                ; Put length in CX
  9965.          sub        cx,di
  9966.          jbe        cl1                        ;  branch if no bytes
  9967.          mov        al,0Ah                        ; Search for linefeeds
  9968.  cl0:        jcxz        cl1                        ; Exit loop if count zero
  9969.          repne scasb                        ; Do search
  9970.          jne        cl1                        ;  branch if none found
  9971.          inc        dx                        ; Increment count
  9972.          jmp        short cl0                ; Loop
  9973.  cl1:        mov        ax,dx                        ; Return line count in AX
  9974.          pop        es
  9975.          pop        di
  9976.          pop        bp
  9977.          ret
  9978.  _countlines endp
  9979.  
  9980.  
  9981.  ; char                        *findlist(buffer,bufend)
  9982.  ; char                        *buffer;        /* Buffer to search */
  9983.  ; char                        *bufend;        /* End of buffer */
  9984.  
  9985.  savesi        equ        word ptr [bp-2]
  9986.  endbyte        equ        byte ptr [bp-4]
  9987.  
  9988.  stringnode struc
  9989.          s_alt        dw        ?                ; List of alternate portions
  9990.          s_suf        dw        ?                ; Pointer to suffix string li
  9991.          s_must        dw        ?                ; Length of portion that mus
  9992.  stringnode ends
  9993.  
  9994.          EVEN
  9995.  
  9996.  flworker dw        findsubi, findsub        ; Worker dispatch table
  9997.  
  9998.          public        _findlist
  9999.  _findlist proc        near
  10000.          ASSUME        DS:DGROUP, ES:NOTHING, SS:DGROUP
  10001.  
  10002.          push        bp
  10003.          mov        bp,sp
  10004.          sub        sp,4                        ; Make room for local vars
  10005.          push        di
  10006.          push        si
  10007.          push        ds
  10008.          pop        es
  10009.      ASSUME        ES:DGROUP
  10010.  
  10011.  ;        We mark the end of our search buffer with 0FFh so that
  10012.  ;        any comparisons that might run past the end of the buffer
  10013.  ;        will fail on the 0FFh.  We choose 0FFh so that if the
  10014.  ;        comparison fails on it, it will always appear as though
  10015.  ;        the string in the buffer is greater that the string in
  10016.  ;        the search list.  This will prevent us from stopping
  10017.  ;        the search too soon.  Of course, we must restore the byte
  10018.  ;        when we're done.
  10019.  
  10020.          mov        bx,bufend                ; BX = end of buffer
  10021.          mov        al,0FFh                        ; End marker
  10022.          xchg        byte ptr [bx],al        ; AL = byte after end of buffer
  10023.          mov        endbyte,al                ; Save the byte
  10024.  
  10025.          mov        cx,bx                        ; CX = end of buffer
  10026.          mov        si,buffer                ; SI = buffer
  10027.          sub        cx,si                        ; CX = buffer length
  10028.          jbe        fl1                        ;  no match if empty buffer
  10029.          mov        bx,offset dgroup:_transtab ; BX = translation table addres
  10030.  
  10031.          mov        di,_casesen                ; Get flag
  10032.          shl        di,1                        ; Scale to word index
  10033.          call        cs:flworker[di]                ; Call helper
  10034.          jc        fl1                        ;  branch if no match
  10035.  
  10036.  ;        We have a match
  10037.  ;
  10038.  ;        SI = offset of first character past end of matched string
  10039.  ;        savesi = offset of first character past start of matched string
  10040.  
  10041.          mov        ax,savesi                ; AX = 1st char past start
  10042.          dec        ax                        ; AX = start of matched string
  10043.          jmp        short fl2
  10044.  
  10045.  ;        We did not find a match
  10046.  
  10047.  fl1:
  10048.          xor        ax,ax                        ; Return NULL
  10049.  
  10050.  ;        Restore end byte before leaving
  10051.  
  10052.  fl2:
  10053.          mov        bx,bufend                ; BX = end of buffer
  10054.          mov        dl,endbyte                ; DL = end byte
  10055.          mov        [bx],dl                        ; Restore byte
  10056.  
  10057.          pop        si
  10058.          pop        di
  10059.          mov        sp,bp
  10060.          pop        bp
  10061.          ret
  10062.  
  10063.  _findlist endp
  10064.  
  10065.  
  10066.  ;***        findsub - case-sensitive worker for _findlist
  10067.  ;
  10068.  ;        This function does most of the work for
  10069.  ;        case-sensitive multi-string searches.
  10070.  ;
  10071.  ;        ENTRY        BX = address of translation table
  10072.  ;                CX = number of bytes left in buffer
  10073.  ;                DS:SI = buffer pointer
  10074.  ;                SS:BP = pointer to stack frame for _findlist
  10075.  ;        EXIT        Carry set
  10076.  ;                    No match
  10077.  ;                Carry clear
  10078.  ;                    DS:SI = pointer to first character after match
  10079.  ;        USES        AX, CX, DX, DI, SI, Flags
  10080.  
  10081.          EVEN
  10082.  
  10083.          public        findsub, fs0, fs1, fs2, fs3, fs4, fs5, fs6
  10084.  findsub        proc        near
  10085.          ASSUME        DS:DGROUP, ES:DGROUP, SS:DGROUP
  10086.  
  10087.  fs0:
  10088.          xor        ax,ax                        ; AH = 0
  10089.  
  10090.  ;        AH = 0
  10091.  ;        BX = address of translation table
  10092.  ;        CX = number of bytes left in buffer
  10093.  ;        SI = buffer pointer
  10094.  ;        DS = ES = SS = DGROUP
  10095.  
  10096.  fs1:
  10097.          lodsb                                ; Character in AL
  10098.          xlat byte ptr [bx]                ; Translate character to index
  10099.          or        al,al                        ; Zero means invalid 1st byte
  10100.          loopz        fs1                        ;  if so, try next character
  10101.  
  10102.  ;        Either the zero bit is set, meaning the buffer is empty,
  10103.  ;        or the zero bit is clear, meaning we have a valid first
  10104.  ;        character.  Either way, CX has been decremented.
  10105.  
  10106.          jz        fs6                        ;  branch if buffer empty
  10107.          mov        savesi,si                ; Save buffer pointer
  10108.          shl        ax,1                        ; Scale to word index
  10109.          mov        di,ax
  10110.          mov        di,_stringlist[di]        ; DI points to string record
  10111.          or        di,di                        ; One byte match? (OR clears c
  10112.          jz        fs3                        ;  yes, skip ahead
  10113.  
  10114.  ;        Loop to search for match.
  10115.  ;        BX = address of translation table
  10116.  ;        DI = pointer to string record
  10117.  ;        SI = pointer into buffer
  10118.  
  10119.  fs2:
  10120.          mov        cx,[di].s_must                ; CX = length of string
  10121.          sub        di,cx                        ; DI = pointer to string
  10122.          mov        dx,si                        ; Save pointer to start of su
  10123.          repe cmpsb                        ; Strings match?
  10124.          ja        fs4                        ;  no, try alternate if follows
  10125.          jb        fs5                        ;  no, cannot be in this list
  10126.          add        di,cx                        ; DI = pointer to string reco
  10127.          mov        di,[di].s_suf                ; Get pointer to suffix strin
  10128.          or        di,di                        ; Is there one? (OR clears car
  10129.          jnz        fs2                        ;  yes, keep looking
  10130.  
  10131.  ;        Match found
  10132.  
  10133.  fs3:
  10134.          ret                                ;  no, we have a match
  10135.  
  10136.  ;        Try alternate suffix
  10137.  
  10138.  fs4:
  10139.          add        di,cx                        ; DI = pointer to string reco
  10140.          mov        di,[di].s_alt                ; Get pointer to alternate
  10141.          mov        si,dx                        ; Restore SI to start of suff
  10142.          or        di,di                        ; Is there one?
  10143.          jnz        fs2                        ;  yes, loop
  10144.  
  10145.  ;        Try new first character
  10146.  
  10147.  fs5:
  10148.          mov        cx,bufend                ; CX = end of buffer
  10149.          mov        si,savesi                ; Restore SI to saved value
  10150.          sub        cx,si                        ; CX = length of buffer
  10151.          ja        short fs0                ; Try next character in buffer
  10152.  
  10153.  ;        No match
  10154.  
  10155.  fs6:
  10156.          stc                                ; No match
  10157.          ret
  10158.  
  10159.  findsub        endp
  10160.  
  10161.  
  10162.  ;***        findsubi - case-insensitive worker for _findlist
  10163.  ;
  10164.  ;        This function does most of the work for
  10165.  ;        case-insensitive multi-string searches.
  10166.  ;
  10167.  ;        ENTRY        BX = address of translation table
  10168.  ;                CX = number of bytes left in buffer
  10169.  ;                DS:SI = buffer pointer
  10170.  ;                SS:BP = pointer to stack frame for _findlist
  10171.  ;        EXIT        Carry set
  10172.  ;                    No match
  10173.  ;                Carry clear
  10174.  ;                    DS:SI = pointer to first character after match
  10175.  ;        USES        AX, CX, DX, DI, SI, Flags
  10176.  
  10177.          EVEN
  10178.  
  10179.          public        findsubi
  10180.  findsubi proc        near
  10181.          ASSUME        DS:DGROUP, ES:DGROUP, SS:DGROUP
  10182.  
  10183.  fsi0:
  10184.          xor        ax,ax                        ; AH = 0
  10185.  
  10186.  ;        AH = 0
  10187.  ;        BX = address of translation table
  10188.  ;        CX = number of bytes left in buffer
  10189.  ;        SI = buffer pointer
  10190.  ;        DS = ES = SS = DGROUP
  10191.  
  10192.  fsi1:
  10193.          lodsb                                ; Character in AL
  10194.          xlat byte ptr [bx]                ; Translate character to index
  10195.          or        al,al                        ; Zero means invalid 1st byte
  10196.          loopz        fsi1                        ;  if so, try next character
  10197.  
  10198.  ;        Either the zero bit is set, meaning the buffer is empty,
  10199.  ;        or the zero bit is clear, meaning we have a valid first
  10200.  ;        character.  Either way, CX has been decremented.
  10201.  
  10202.          jz        fsi7                        ;  branch if buffer empty
  10203.          mov        savesi,si                ; Save buffer pointer
  10204.          shl        ax,1                        ; Scale to word index
  10205.          mov        di,ax
  10206.          mov        di,_stringlist[di]        ; DI points to string record
  10207.          or        di,di                        ; One byte match? (OR clears c
  10208.          jz        fsi4                        ;  yes, skip ahead
  10209.  
  10210.  ;        Loop to search for match.
  10211.  ;        BX = address of translation table
  10212.  ;        DI = pointer to string record
  10213.  ;        SI = pointer into buffer
  10214.  
  10215.  fsi2:
  10216.          mov        cx,[di].s_must                ; CX = length of string
  10217.          sub        di,cx                        ; DI = pointer to string
  10218.          mov        dx,si                        ; Save pointer to start of su
  10219.  fsi3:        lodsb                                ; Byte in AL, SI = SI + 1
  10220.          mov        ah,[di]                        ; Byte in AH, DI = DI + 1
  10221.          inc        di
  10222.          or        ax,2020h                ; Fold bytes onto lower case
  10223.          cmp        al,ah                        ; Compare bytes
  10224.          loope        fsi3                        ; Loop while same
  10225.          ja        fsi5                        ;  no, try alternate if follows
  10226.          jb        fsi6                        ;  no, cannot be in this list
  10227.          add        di,cx                        ; DI = pointer to string reco
  10228.          mov        di,[di].s_suf                ; Get pointer to suffix strin
  10229.          or        di,di                        ; Is there one? (OR clears car
  10230.          jnz        fsi2                        ;  yes, keep looking
  10231.  
  10232.  ;        Match found
  10233.  
  10234.  fsi4:
  10235.          ret                                ;  no, we have a match
  10236.  
  10237.  ;        Try alternate suffix
  10238.  
  10239.  fsi5:
  10240.          add        di,cx                        ; DI = pointer to string reco
  10241.          mov        di,[di].s_alt                ; Get pointer to alternate
  10242.          mov        si,dx                        ; Restore SI to start of suff
  10243.          or        di,di                        ; Is there one?
  10244.          jnz        fsi2                        ;  yes, loop
  10245.  
  10246.  ;        Try new first character
  10247.  
  10248.  fsi6:
  10249.          mov        cx,bufend                ; CX = end of buffer
  10250.          mov        si,savesi                ; Restore SI to saved value
  10251.          sub        cx,si                        ; CX = length of buffer
  10252.          ja        short fsi0                ; Try next character in buffer
  10253.  
  10254.  ;        No match
  10255.  
  10256.  fsi7:
  10257.          stc                                ; No match
  10258.          ret
  10259.  
  10260.  findsubi endp
  10261.  
  10262.  
  10263.  ; int                        strnspn(s,t,n)
  10264.  ; char                        *s;                /* String to search */
  10265.  ; char                        *t;                /* Target list */
  10266.  ; int                        n;                /* Length of s */
  10267.  
  10268.  s        equ        word ptr [bp+retlen+2]
  10269.  t        equ        word ptr [bp+retlen+4]
  10270.  n        equ        word ptr [bp+retlen+6]
  10271.  
  10272.          EVEN
  10273.  
  10274.          public        _strnspn
  10275.  _strnspn proc        near
  10276.          push        bp
  10277.          mov        bp,sp
  10278.          push        di
  10279.          push        si
  10280.          push        ds
  10281.          pop        es
  10282.          cld
  10283.          mov        bx,t                        ; BX = t
  10284.          mov        di,bx                        ; DI = t
  10285.          xor        al,al                        ; Search for 0 byte
  10286.          mov        cx,0FFFFh
  10287.          repne scasb
  10288.          dec        di                        ; Back up to 0
  10289.          sub        di,bx                        ; DI = length of t
  10290.          jz        spn1                        ; Done if length of t is 0
  10291.          mov        dx,di                        ; DX = length of t
  10292.          mov        si,s                        ; SI = s
  10293.          mov        cx,n                        ; CX = length of s
  10294.          jcxz        spn1                        ; Check for null string
  10295.          push        bp
  10296.  spn0:        lodsb                                ; AL = next char in s
  10297.          mov        bp,cx                        ; BP = length of s
  10298.          mov        cx,dx                        ; CX = length of t
  10299.          mov        di,bx                        ; DI = t
  10300.          repne scasb                        ; Scan until match found
  10301.          mov        cx,bp                        ; CX = length of s
  10302.          loope        spn0                        ; Loop if match found
  10303.          pop        bp
  10304.          je        spn1                        ; Skip ahead if end of s reache
  10305.          dec        si                        ; Back up one char
  10306.  spn1:        sub        si,s                        ; SI = length of prefix
  10307.          mov        ax,si                        ; AX = length of prefix
  10308.          pop        si
  10309.          pop        di
  10310.          pop        bp
  10311.          ret
  10312.  _strnspn endp
  10313.  
  10314.  
  10315.  ; int                        strncspn(s,t,n)
  10316.  ; char                        *s;                /* String to search */
  10317.  ; char                        *t;                /* Target list */
  10318.  ; int                        n;                /* Length of s */
  10319.  
  10320.          EVEN
  10321.  
  10322.          public        _strncspn
  10323.  _strncspn proc        near
  10324.          push        bp
  10325.          mov        bp,sp
  10326.          push        di
  10327.          push        si
  10328.          push        ds
  10329.          pop        es
  10330.          cld
  10331.          mov        bx,t                        ; BX = t
  10332.          mov        di,bx                        ; DI = t
  10333.          xor        al,al                        ; Search for 0 byte
  10334.          mov        cx,0FFFFh
  10335.          repne scasb
  10336.          dec        di                        ; Back up to 0
  10337.          sub        di,bx                        ; DI = length of t
  10338.          mov        ax,n                        ; Assume length of t is 0
  10339.          jz        cspn2                        ; Done if length of t is 0
  10340.          mov        dx,di                        ; DX = length of t
  10341.          mov        si,s                        ; SI = s
  10342.          mov        cx,ax                        ; CX = length of s
  10343.          jcxz        cspn1                        ; Check for null string
  10344.          push        bp
  10345.  cspn0:        lodsb                                ; AL = next char in s
  10346.          mov        bp,cx                        ; BP = length of s
  10347.          mov        cx,dx                        ; CX = length of t
  10348.          mov        di,bx                        ; DI = t
  10349.          repne scasb                        ; Scan until match found
  10350.          mov        cx,bp                        ; CX = length of s
  10351.          loopne        cspn0                        ; Loop if match not found
  10352.          pop        bp
  10353.          jne        cspn1                        ; Skip ahead if end of s reac
  10354.          dec        si                        ; Back up one char
  10355.  cspn1:        sub        si,s                        ; SI = length of prefix
  10356.          mov        ax,si                        ; AX = length of prefix
  10357.  cspn2:        pop        si
  10358.          pop        di
  10359.          pop        bp
  10360.          ret
  10361.  _strncspn endp
  10362.  
  10363.  
  10364.  ;        cmpsen - case-sensitive comparison
  10365.  ;
  10366.  ;        ENTRY        DS:SI = buffer
  10367.  ;                ES:DI = string
  10368.  ;                CX = length of string
  10369.  ;        EXIT        CX = length of string unused
  10370.  ;                DI = unused portion of string
  10371.  ;                Z set
  10372.  ;                    match found
  10373.  ;                Z clear
  10374.  ;                    no match
  10375.  ;        USES        CX, DI, SI, Flags
  10376.  
  10377.          EVEN
  10378.  
  10379.  cmpsen        proc        near
  10380.          repe cmpsb
  10381.          ret
  10382.  cmpsen        endp
  10383.  
  10384.  
  10385.  ;        cmpinsen - case-insensitive comparison
  10386.  ;
  10387.  ;        ENTRY        DS:SI = buffer
  10388.  ;                ES:DI = string
  10389.  ;                CX = length of string
  10390.  ;        EXIT        CX = length of string unused
  10391.  ;                DI = unused portion of string
  10392.  ;                Z set
  10393.  ;                    match found
  10394.  ;                Z clear
  10395.  ;                    no match
  10396.  ;        USES        AX, CX, DI, SI, Flags
  10397.  
  10398.          EVEN
  10399.  
  10400.  cmpinsen proc        near
  10401.  cmpi0:        lodsb                                ; Byte in AL, SI = SI + 1
  10402.          mov        ah,[di]                        ; Byte in AH, DI = DI + 1
  10403.          inc        di
  10404.          or        ax,2020h                ; Fold bytes onto lower case
  10405.          cmp        al,ah                        ; Compare bytes
  10406.          loope        cmpi0                        ; Loop while same
  10407.          ret
  10408.  cmpinsen endp
  10409.  
  10410.  
  10411.  ; void                        matchstrings(s1,s2,len,nmatched,leg)
  10412.  ; char                        *s1;                /* First string */
  10413.  ; char                        *s2;                /* Second string */
  10414.  ; int                        len;                /* Length */
  10415.  ; int                        *nmatched;        /* Number of bytes matched */
  10416.  ; int                        *leg;                /* Less than, equal, greate
  10417.  
  10418.  cm_s1                equ        word ptr [bp+retlen+2]
  10419.  cm_s2                equ        word ptr [bp+retlen+4]
  10420.  cm_len                equ        word ptr [bp+retlen+6]
  10421.  cm_nmatched        equ        word ptr [bp+retlen+8]
  10422.  cm_leg                equ        word ptr [bp+retlen+10]
  10423.  
  10424.          EVEN
  10425.  
  10426.          public        _matchstrings
  10427.  _matchstrings proc near
  10428.          ASSUME        DS:DGROUP, ES:NOTHING, SS:DGROUP
  10429.  
  10430.          push        bp
  10431.          mov        bp,sp
  10432.          push        di
  10433.          push        si
  10434.          push        ds
  10435.          pop        es
  10436.      ASSUME        ES:DGROUP
  10437.          mov        di,cm_s2
  10438.          mov        si,cm_s1
  10439.          mov        cx,cm_len
  10440.          cmp        _casesen,0
  10441.          je        cm0
  10442.          call        cmpsen
  10443.          jmp        short cm1
  10444.  cm0:        call        cmpinsen
  10445.  cm1:        mov        bx,cm_leg
  10446.          mov        word ptr [bx],0                ; Assume equal
  10447.          jz        cm2                        ;  yes, skip ahead
  10448.          mov        word ptr [bx],1                ; Assume greater than
  10449.          jg        cm1a                        ;  yes, skip ahead
  10450.          mov        word ptr [bx],-1        ; Less than
  10451.  cm1a:        dec        si
  10452.  cm2:        sub        si,cm_s1
  10453.          mov        bx,cm_nmatched
  10454.          mov        [bx],si
  10455.          pop        si
  10456.          pop        di
  10457.          pop        bp
  10458.          ret
  10459.  
  10460.  _matchstrings endp
  10461.  
  10462.  
  10463.  ; int                        strcmp(s1,s2)
  10464.  ; char                        *s1;                /* First string */
  10465.  ; char                        *s2;                /* Second string */
  10466.  
  10467.          public        _strcmp
  10468.  _strcmp        proc        near
  10469.          push        bp
  10470.          mov        bp,sp
  10471.          push        di
  10472.          push        si
  10473.          push        ds
  10474.          pop        es
  10475.          mov        si,[bp+4]                ; DS:SI = s1
  10476.          mov        di,[bp+6]                ; ES:DI = s2
  10477.  sc0:        lodsb                                ; AL = *s1++
  10478.          scasb                                ; AL - *s2++
  10479.          jne        sc1                        ;  branch if no match
  10480.          or        al,al                        ; End of s1?
  10481.          jne        sc0                        ;  no, loop
  10482.          cbw                                ; AX = 0
  10483.          jmp        short sc2                ; Exit
  10484.  sc1:        mov        ax,1                        ; Assume s1 > s2
  10485.          jg        sc2                        ;  yes, branch
  10486.          neg        ax                        ; s1 < s2
  10487.  sc2:        pop        si
  10488.          pop        di
  10489.          pop        bp
  10490.          ret
  10491.  _strcmp        endp
  10492.  
  10493.  
  10494.          public        _bpt
  10495.  _bpt        proc        near
  10496.          int        3
  10497.          ret
  10498.  _bpt        endp
  10499.  
  10500.  _text        ends
  10501.  
  10502.  _data        segment word public 'data'
  10503.  _data        ends
  10504.  
  10505.  end
  10506.  
  10507.  
  10508.  DATA.C
  10509.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\OPENDLG\DATA.C
  10510.  
  10511.  /***************************************************************************\
  10512.  * DATA.C -- This file contains per process global variables
  10513.  * Created by Microsoft Corporation, 1989
  10514.  \***************************************************************************/
  10515.  
  10516.  #define NO_DOS
  10517.  #define NO_GPI
  10518.  #include "tool.h"
  10519.  
  10520.  /*
  10521.     This library uses a NON SHARED DATA selector.  This means each
  10522.     process using the library gets its own selector, and also that
  10523.     values cannot be shared and must be recreated for each process.
  10524.  */
  10525.  
  10526.  HMODULE vhModule;            /* Library module handle */
  10527.  HHEAP  vhheap;               /* Library heap */
  10528.  
  10529.  PSTR   vrgsz[CSTRINGS];      /* Array of pointer to our strings (indexed
  10530.                                  by IDS_... */
  10531.  
  10532.  
  10533.  DCALC.C
  10534.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CALC\DCALC\DCALC.C
  10535.  
  10536.  /****************************** Module Header ******************************\
  10537.  * Module Name:        dcalc.c - Dialog form of the Calc application
  10538.  *
  10539.  * OS/2 Presentation Manager version of Calc, ported from Windows version
  10540.  *
  10541.  * Created by Microsoft Corporation, 1989
  10542.  *
  10543.  \***************************************************************************/
  10544.  
  10545.  #define INCL_DEV
  10546.  #define INCL_DOSPROCESS
  10547.  #define INCL_DOSSEMAPHORES
  10548.  #define INCL_DOSNLS
  10549.  #define INCL_ERRORS
  10550.  #define INCL_WINBUTTONS
  10551.  #define INCL_WINCLIPBOARD
  10552.  #define INCL_WINDIALOGS
  10553.  #define INCL_WINFRAMEMGR
  10554.  #define INCL_WININPUT
  10555.  #define INCL_WINMENUS
  10556.  #define INCL_WINMESSAGEMGR
  10557.  #define INCL_WINPOINTERS
  10558.  #define INCL_WINSWITCHLIST
  10559.  #define INCL_WINTRACKRECT
  10560.  #define INCL_WINWINDOWMGR
  10561.  #include <os2.h>
  10562.  #include <string.h>
  10563.  #include <stdlib.h>
  10564.  #include <stdio.h>
  10565.  #include "dcalc.h"
  10566.  
  10567.  /************* GLOBAL VARIABLES         */
  10568.  
  10569.  char chLastKey, currkey;
  10570.  char szCalcClass[] = "Calculator";
  10571.  char szTitle[30];
  10572.  char szreg1[20], szreg2[20], szmem[20], szregx[20];
  10573.  /* hope 20 is enough for kanji error string */
  10574.  char szErrorString[20], szPlusMinus[2];
  10575.  short charwidth, charheight;
  10576.  int aspectx, aspecty, nchszstr;
  10577.  extern BOOL fError  = FALSE;
  10578.  BOOL fValueInMemory = FALSE;
  10579.  BOOL fMDown = FALSE;
  10580.  UCHAR mScan = 0;
  10581.  
  10582.  #define TOLOWER(x)   ( (((x) >= 'A') && ((x) <= 'Z')) ? (x)|0x20 : (x))
  10583.  #define WIDTHCONST  28
  10584.  #define CXCHARS     37
  10585.  #define CYCHARS     13
  10586.  
  10587.  HAB hab;
  10588.  HDC hdcLocal;                            /* Local used for button bitmap */
  10589.  HPS hpsLocal;
  10590.  HDC hdcSqr;                            /* Sqr used for square-root bitmap */
  10591.  HPS hpsSqr;
  10592.  HBITMAP hbmLocal, hbmSqr;
  10593.  HMQ  hmqCalc            = NULL;
  10594.  
  10595.  HWND hwndCalc            = NULL,
  10596.       hwndMenu            = NULL;
  10597.  
  10598.  HPOINTER hptrFinger = NULL,
  10599.           hptrIcon   = NULL;
  10600.  
  10601.  DEVOPENSTRUC dop =                    /* used by DevOpenDC */
  10602.  {
  10603.      NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL
  10604.  };
  10605.  
  10606.  static char bButtonValues[] =            /* Button values */
  10607.  {
  10608.      0xBC, 0xBB, 0xBA, 0xB9,  '0',  '1',  '2',  '3',  '4',
  10609.       '5',  '6',  '7',  '8',  '9',  '.',  '/',  '*',  '-',
  10610.       '+',  'q',  '%',  'c',  '=', 0xB1, NULL
  10611.  };
  10612.  
  10613.  /************* PROCEDURE DECLARATIONS   */
  10614.  
  10615.  MPARAM EXPENTRY AboutDlgProc(HWND, USHORT, MPARAM, MPARAM);
  10616.  BOOL CalcInit(VOID);
  10617.  VOID CalcPaint( HWND, HPS);
  10618.  MRESULT EXPENTRY fnDlgCalc(HWND, USHORT, MPARAM, MPARAM);
  10619.  VOID cdecl main(VOID);
  10620.  VOID DataXCopy( VOID);
  10621.  VOID DataXPaste( VOID);
  10622.  VOID DrawNumbers( HPS);
  10623.  VOID Evaluate(BYTE);
  10624.  VOID InitCalc( VOID);
  10625.  BOOL InterpretChar( CHAR);
  10626.  VOID ProcessKey(HWND, WPOINT *);
  10627.  char Translate(WPOINT *);
  10628.  VOID UpdateDisplay( VOID);
  10629.  
  10630.  
  10631.  
  10632.  /********************************************************************
  10633.     Write the appropriate number or error string to the display area
  10634.     and mark memory-in-use if appropriate.
  10635.   */
  10636.  
  10637.  BYTE aszDisplayBuff[20];
  10638.  
  10639.  VOID UpdateDisplay()
  10640.  {
  10641.      strcpy(aszDisplayBuff, fError? "Error" :szreg1);
  10642.      strcat(aszDisplayBuff, fValueInMemory? " M" : "  ");
  10643.  
  10644.      WinSetDlgItemText(hwndCalc, TXT_RESULT_DISPLAY, aszDisplayBuff);
  10645.  }
  10646.  
  10647.  
  10648.  /**********************************************************************
  10649.      Display helpful info
  10650.   */
  10651.  
  10652.  MPARAM EXPENTRY AboutDlgProc(hwnd, msg, mp1, mp2)
  10653.  HWND hwnd;
  10654.  USHORT msg;
  10655.  MPARAM mp1;
  10656.  MPARAM mp2;
  10657.  {
  10658.      if (msg == WM_COMMAND)
  10659.      {
  10660.          WinDismissDlg(hwnd, TRUE);
  10661.          return(MPFROMSHORT(TRUE));
  10662.      }
  10663.      else return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  10664.  }
  10665.  
  10666.  
  10667.  /**********************************************************************
  10668.      General initialization
  10669.   */
  10670.  
  10671.  BOOL CalcInit()
  10672.  {
  10673.      hab = WinInitialize(0);
  10674.  
  10675.      hmqCalc = WinCreateMsgQueue( hab, 0);
  10676.  
  10677.      return(TRUE);
  10678.  }
  10679.  
  10680.  /**********************************************************************
  10681.      main procedure
  10682.   */
  10683.  
  10684.  VOID cdecl main()
  10685.  {
  10686.      QMSG qmsg;
  10687.  
  10688.      if (!CalcInit()) {                            /* general initialization *
  10689.          WinAlarm(HWND_DESKTOP, 0xffff);
  10690.          goto exit;
  10691.      }
  10692.  
  10693.      WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP, fnDlgCalc, NULL, CALCDLG, NULL);
  10694.  
  10695.      if (hwndCalc)
  10696.          while (WinGetMsg( hab, (PQMSG)&qmsg, NULL, 0, 0))
  10697.              WinDispatchMsg( hab, (PQMSG)&qmsg);
  10698.  
  10699.  exit:                                            /* clean up */
  10700.  
  10701.      if (hwndMenu)      WinDestroyWindow(hwndMenu);
  10702.  
  10703.      WinDestroyMsgQueue(hmqCalc);
  10704.      WinTerminate(hab);
  10705.  
  10706.      DosExit(EXIT_PROCESS, 0);                    /* exit without error */
  10707.  }
  10708.  
  10709.  
  10710.  /*************************************************************************
  10711.     Calc Dialog Window Procedure
  10712.   */
  10713.  
  10714.  
  10715.  USHORT        idProcess, idThread;
  10716.  SWCNTRL swc;
  10717.  HSWITCH hsw;
  10718.  USHORT        usWidthCalc, usHeightCalc;
  10719.  
  10720.  MRESULT EXPENTRY fnDlgCalc(hwnd, msg, mp1, mp2)
  10721.  HWND hwnd;
  10722.  USHORT msg;
  10723.  MPARAM mp1;
  10724.  MPARAM mp2;
  10725.  {
  10726.      RECTL rectl;
  10727.      BOOL fClip;
  10728.      USHORT fi, idCtrl;
  10729.      MRESULT mresult;
  10730.      USHORT  afSWP;
  10731.      PSWP    pswp;
  10732.  
  10733.      static BOOL fMinimized;
  10734.  
  10735.  
  10736.      switch (msg)
  10737.      {
  10738.      case WM_INITDLG:
  10739.  
  10740.  /* Set up the global state assumed by the dialog.
  10741.   */
  10742.          hwndCalc = hwnd;
  10743.          hwndMenu = WinLoadMenu(hwnd, NULL, IDR_CALC);
  10744.  
  10745.          fMinimized = FALSE;
  10746.  
  10747.          hptrFinger = WinLoadPointer(HWND_DESKTOP, (HMODULE)NULL, IDP_FINGER);
  10748.          hptrIcon   = WinLoadPointer(HWND_DESKTOP, (HMODULE)NULL, IDR_CALC);
  10749.  
  10750.          WinSetWindowULong(hwndCalc, QWL_STYLE,
  10751.                            FS_ICON | WinQueryWindowULong(hwndCalc, QWL_STYLE)
  10752.                           );
  10753.  
  10754.          WinSendMsg(hwndCalc, WM_SETICON,     (MPARAM) hptrIcon, 0L);
  10755.          WinSendMsg(hwndCalc, WM_UPDATEFRAME, (MPARAM) 0L,        0L);
  10756.  
  10757.          WinQueryWindowRect(hwndCalc, &rectl);
  10758.           usWidthCalc= (SHORT) (rectl.xRight - rectl.xLeft);
  10759.          usHeightCalc= (SHORT) (rectl.yTop   - rectl.yBottom);
  10760.  
  10761.          WinQueryWindowProcess(hwndCalc, &idProcess, &idThread);
  10762.  
  10763.          WinLoadString(NULL, NULL, 1, 30, (PSZ)szTitle);
  10764.          WinLoadString(NULL, NULL, 2, 20, (PSZ)szErrorString);
  10765.          WinLoadString(NULL, NULL, 3, 2,  (PSZ)szPlusMinus);
  10766.  
  10767.          strcpy(swc.szSwtitle, szTitle);
  10768.          swc.hwnd          = hwndCalc;
  10769.          swc.hwndIcon          = hptrIcon;
  10770.          swc.hprog          = (ULONG)NULL;
  10771.          swc.idProcess          = idProcess;
  10772.          swc.idSession          = (USHORT)0;
  10773.          swc.uchVisibility = SWL_VISIBLE;
  10774.          swc.fbJump          = SWL_JUMPABLE;
  10775.          hsw                  = WinAddSwitchEntry((PSWCNTRL)&swc);
  10776.  
  10777.          InitCalc();                            /* arithmetic initialization *
  10778.  
  10779.          WinSetActiveWindow(HWND_DESKTOP, hwndCalc);
  10780.  
  10781.          WinSetFocus(HWND_DESKTOP, hwndCalc);
  10782.  
  10783.          break;
  10784.  
  10785.      case WM_MINMAXFRAME:
  10786.  
  10787.          pswp= PVOIDFROMMP(mp1);
  10788.  
  10789.          if (pswp->fs & SWP_MINIMIZE) fMinimized= TRUE;
  10790.          else
  10791.              if (pswp->fs & SWP_RESTORE) fMinimized= FALSE;
  10792.  
  10793.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  10794.  
  10795.          break;
  10796.  
  10797.      case WM_DESTROY:
  10798.  
  10799.          WinDestroyPointer(hptrIcon  );        hptrIcon  = NULL;
  10800.          WinDestroyPointer(hptrFinger);        hptrFinger= NULL;
  10801.  
  10802.          break;
  10803.  
  10804.      case WM_INITMENU:
  10805.  
  10806.          fClip = FALSE;
  10807.  
  10808.          if (WinOpenClipbrd(NULL))
  10809.          {
  10810.              fClip = WinQueryClipbrdFmtInfo(NULL, CF_TEXT, (USHORT FAR *)&fi);
  10811.              WinCloseClipbrd(NULL);
  10812.          }
  10813.  
  10814.          WinSendMsg((HWND)mp2, MM_SETITEMATTR,
  10815.                     (MPARAM) MAKELONG(CMD_PASTE, TRUE),
  10816.                     (MPARAM) MAKELONG(MIA_DISABLED, fClip ? 0 : MIA_DISABLED))
  10817.          break;
  10818.  
  10819.      case WM_ADJUSTWINDOWPOS:
  10820.  
  10821.          mresult= WinDefDlgProc(hwnd, msg, mp1, mp2);
  10822.  
  10823.          if (fMinimized) return(mresult);
  10824.  
  10825.          afSWP= (pswp= (PSWP) mp1)->fs;
  10826.  
  10827.          if (         afSWP & (SWP_SIZE     | SWP_MAXIMIZE)
  10828.              && !(afSWP &  SWP_MINIMIZE)
  10829.             )
  10830.          {
  10831.              pswp->y += pswp->cy - usHeightCalc;
  10832.              pswp->cx =        usWidthCalc;
  10833.              pswp->cy = usHeightCalc;
  10834.          }
  10835.  
  10836.          return(mresult);
  10837.  
  10838.  
  10839.      case WM_COMMAND:
  10840.  
  10841.          fError = FALSE;
  10842.  
  10843.          idCtrl= SHORT1FROMMP(mp1);
  10844.  
  10845.          if (   SHORT1FROMMP(mp2) == BN_CLICKED
  10846.              && idCtrl >= BUTTON_MC
  10847.              && idCtrl <= BUTTON_CHANGE_SIGN
  10848.             )
  10849.          {
  10850.              Evaluate(bButtonValues[idCtrl-BUTTON_MC]);
  10851.              UpdateDisplay();
  10852.          }
  10853.          else
  10854.              switch(idCtrl)
  10855.              {
  10856.              case CMD_COPY:
  10857.                  DataXCopy();                        /* copy to clipboard */
  10858.                  break;
  10859.              case CMD_PASTE:
  10860.                  DataXPaste();                        /* paste from clipboard
  10861.                  break;
  10862.              case CMD_EXIT:
  10863.                  WinPostMsg(hwndCalc, WM_QUIT, 0L, 0L);
  10864.                  break;
  10865.              case CMD_ABOUT:
  10866.                  WinDlgBox(HWND_DESKTOP, hwndCalc, (PFNWP)AboutDlgProc, NULL,
  10867.                            1, (PSZ)NULL);
  10868.                  break;
  10869.              }
  10870.          break;
  10871.  
  10872.      case WM_CLOSE:
  10873.          WinPostMsg(hwndCalc, WM_QUIT, 0L, 0L);
  10874.          break;
  10875.  
  10876.      case WM_CONTROLPOINTER:
  10877.          if (!fMinimized) return(hptrFinger);
  10878.          else return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  10879.  
  10880.      case WM_MOUSEMOVE:
  10881.          if (!fMinimized) WinSetPointer(HWND_DESKTOP, hptrFinger);
  10882.          break;
  10883.  
  10884.      case WM_BUTTON1DOWN:
  10885.  
  10886.          return(WinDefDlgProc(hwnd, WM_TRACKFRAME, (MPARAM) TF_MOVE, mp2));
  10887.  
  10888.          break;
  10889.  
  10890.      case WM_CHAR:
  10891.  
  10892.          fError = FALSE;
  10893.          if (SHORT1FROMMP(mp1) & KC_KEYUP)
  10894.          {
  10895.              if (CHAR4FROMMP(mp1) == mScan)
  10896.                     fMDown = FALSE;                 /* 'm' key went up */
  10897.          }
  10898.          else
  10899.          {
  10900.                  if (SHORT1FROMMP(mp1) & KC_CHAR)
  10901.        {
  10902.               if (InterpretChar((UCHAR)(ULONG)(mp2)))
  10903.                    {
  10904.                                  UpdateDisplay();
  10905.                    }
  10906.               else
  10907.                    {
  10908.                                    if (((UCHAR)(ULONG)(mp2)== 'm') || ((UCHAR)
  10909.                              {
  10910.                                          mScan = CHAR4FROMMP(mp1);           /
  10911.                                          fMDown = TRUE;
  10912.                              }
  10913.          }
  10914.                  }
  10915.          }
  10916.          break;
  10917.  
  10918.  
  10919.      case WM_ERASEBACKGROUND:
  10920.          if (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MINIMIZED)
  10921.              WinValidateRect(hwnd, (PRECTL) mp2, TRUE);
  10922.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  10923.          break;
  10924.  
  10925.      case WM_SETFOCUS:
  10926.          if ((HWNDFROMMP(mp1)==hwndCalc) && !mp2);
  10927.              fMDown = FALSE;                        /* since we are losing foc
  10928.  
  10929.      default:
  10930.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  10931.          break;
  10932.      }
  10933.      return(0L);
  10934.  }
  10935.  
  10936.  
  10937.  /*************************************************************************
  10938.      translate & interpret keys (ie. locate in logical keyboard)
  10939.   */
  10940.  
  10941.  BOOL InterpretChar(ch)
  10942.  register CHAR ch;
  10943.  {
  10944.      BOOL fDone;
  10945.      CHAR *chstep;
  10946.  
  10947.      fDone = FALSE;
  10948.      chstep = bButtonValues;
  10949.      switch (ch)
  10950.      {
  10951.      case 'n':
  10952.          ch = szPlusMinus[0];
  10953.          break;
  10954.      case 27:                        /* xlate Escape into 'c' */
  10955.          ch = 'c';
  10956.          break;
  10957.      case '\r':                      /* xlate Enter into '=' */
  10958.          ch = '=';
  10959.          break;
  10960.      }
  10961.  
  10962.      if (fMDown)                     /* Do memory keys */
  10963.      {
  10964.          switch (ch)
  10965.          {
  10966.          case 'c':
  10967.          case 'C':
  10968.              ch = '\274';
  10969.              break;
  10970.          case 'r':
  10971.          case 'R':
  10972.              ch = '\273';
  10973.              break;
  10974.          case '+':
  10975.              ch = '\272';
  10976.              break;
  10977.          case '-':
  10978.              ch = '\271';
  10979.              break;
  10980.          }
  10981.      }
  10982.  
  10983.      while (!fDone && *chstep)
  10984.      {
  10985.          if (*chstep++ == ch)
  10986.              fDone = TRUE;                /* char found in logical keyboard */
  10987.      }
  10988.  
  10989.      if (fDone)
  10990.      {
  10991.          Evaluate(ch);
  10992.      }
  10993.  
  10994.      return (fDone);
  10995.  }
  10996.  
  10997.  
  10998.  DDEML.C
  10999.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DDEML.C
  11000.  
  11001.  /****************************** Module Header ******************************\
  11002.  * Module Name: DDE.C
  11003.  *
  11004.  * DDE Manager main module - Contains all exported Dde functions.
  11005.  *
  11006.  * Created: 12/12/88 Sanford Staab
  11007.  *
  11008.  * Copyright (c) 1988, 1989  Microsoft Corporation
  11009.  * 4/5/89        sanfords        removed need for hwndFrame registration param
  11010.  * 6/5/90        sanfords        Fixed callbacks so they are blocked during
  11011.  *                               timeouts.
  11012.  *                               Fixed SendDDEInit allocation bug.
  11013.  *                               Added hApp to ConvInfo structure.
  11014.  *                               Allowed QueryConvInfo() to work on server hCo
  11015.  *                               Added FindFrame() to provide an hApp for Serv
  11016.  *                               hConvs.
  11017.  * 6/14/90       sanfords        Altered hDatas so they will work when shared
  11018.  *                               between threads of the same process.  Also
  11019.  *                               added optimization to only have the hsz
  11020.  *                               in the hData for local conversations.
  11021.  * 6/21/90       sanfords        Renamed APIs to Dde....
  11022.  *                               Finished DdeAppNameServer() implementation.
  11023.  *
  11024.  \***************************************************************************/
  11025.  
  11026.  #include "ddemlp.h"
  11027.  #include "version.h"
  11028.  
  11029.  /****** Globals *******/
  11030.  
  11031.  HMODULE hmodDmg = 0;        /* initialized by LoadProc on DLL initialization
  11032.  PFNWP lpfnFrameWndProc = 0;             /* system Frame window procedure */
  11033.  
  11034.  HHEAP hheapDmg = 0;                     /* main DLL heap */
  11035.  
  11036.  PHATOMTBL aAtbls;
  11037.  USHORT cAtbls = 0;
  11038.  USHORT iAtblCurrent = 0;
  11039.  USHORT   cMonitor = 0;
  11040.  DOSFSRSEM FSRSemDmg;                    /* used to protect globals */
  11041.  USHORT cAtoms = 0;                      /* for debugging! */
  11042.  
  11043.  PAPPINFO pAppInfoList = NULL;           /* registered thread data list */
  11044.  USHORT usHugeShift;                     /* for huge segment support */
  11045.  USHORT usHugeAdd;                       /* for huge segment support */
  11046.  COUNTRYCODE syscc;
  11047.  
  11048.  BOOL fInSubset(PCQDATA pcqd, ULONG afCmd);
  11049.  
  11050.  /* PUBDOC START *\
  11051.  DLL overview:
  11052.  
  11053.  This DLL supports standard DDE communication on behalf of its client
  11054.  applications.  It is compatable with most existing DDE programs.  The
  11055.  API interface features object-like abstractions that allow its implementation
  11056.  on and across a variety of platforms.
  11057.  
  11058.  Main features:
  11059.  
  11060.    * HSZ manager:    Allows more efficient handling of numerous character
  11061.                      strings without the limitations of the atom manager.
  11062.  
  11063.    * HDATA manager:  Data container objects allow easy filling, accessing
  11064.                      and reuse of huge amounts of data and allow a
  11065.                      server to efficiently support several clients.
  11066.  
  11067.    * Controled initiates: Supports client to multi-server initiates and
  11068.                      allows a client application to pick and choose which
  11069.                      conversations to keep.
  11070.  
  11071.    * Debugging support: Allows monitoring applications to be easily written
  11072.                      and provides readable error messages.
  11073.  
  11074.    * Huge Segment support: Exports a useful huge segment copy function and
  11075.                      properly handles huge data transfers.
  11076.  
  11077.    * Synchronous communication:  Clients may use a very simple form of
  11078.                      transaction processing that requires little application
  11079.                      support.
  11080.  
  11081.    * Asynchronous communication:  Clients may opt to use queued transfers
  11082.                      freeing them to do other tasks in parellel with DDE.
  11083.  
  11084.    * Callback control:  Applications may selectively suspend DLL callbacks
  11085.                      to themselves when in time critical sections.  Selected
  11086.                      conversations can be blocked while being serviced so
  11087.                      others can be processed by the same thread.
  11088.  
  11089.    * registration notification: All applications using this DLL are notified
  11090.                      whenever any other application registers or unregisters
  11091.                      itself with this DLL.  This enables nameserver support
  11092.                      for DDE.
  11093.  
  11094.    * multiple DDE entity support:  An application can register itself with
  11095.                      any number of application names and can change what
  11096.                      application names it responds to at any time.  Each
  11097.                      registered thread is a seperate DDE entity.
  11098.  
  11099.    * advise loop control:  Advise loops are tracked by the DLL, however
  11100.                      server applications have complete control over
  11101.                      advise loop initiation.
  11102.  
  11103.    * network agent support: Special agent applications can register with this
  11104.                      DLL to represent multiple applications on other machines
  11105.                      or platforms.
  11106.  
  11107.  API specifications:
  11108.  
  11109.  Callback function:
  11110.  
  11111.  EXPENTRY Callback(
  11112.  HCONV hConv,        // holds server conversation handle in most cases
  11113.  HSZ hszTopic,       // holds topic hsz for transaction
  11114.  HSZ hszItem,        // holds item or application hsz for transaction
  11115.  USHORT usFormat,    // holds data format when applicable
  11116.  USHORT usType,      // holds transaction type code
  11117.  HDMGDATA hDmgData); // holds incomming data in most cases
  11118.  
  11119.  This is the definition of the data call-back function that an
  11120.  application must export so that the DDE can initiate interaction
  11121.  with the application when necessary.  This function is refered to in
  11122.  the DdeInitialize() call.
  11123.  
  11124.  The application callback function is very much like a PM window
  11125.  procedure for DDE.  The usType specifies the type of transaction being
  11126.  done.  By ANDing this parameter with XCLASS_MASK and comparing the
  11127.  result with the XCLASS_ constants, the transaction return type
  11128.  expected can be classified.
  11129.  
  11130.  XTYP_ constants also may contain the XTYPF_NOBLOCK flag.  The presence
  11131.  of this flag indicates that the CBR_BLOCK return value from the callback
  11132.  will not be honored by the DDE.  (see DdeEnableCallback() for more
  11133.  information on this concept.)
  11134.  
  11135.  The various transactions are explained below:
  11136.  
  11137.  
  11138.  -----XCLASS_NOTIFICATION class:
  11139.      These are strictly notification messages to an application.  The return
  11140.      value is ignored except in the case of CBR_BLOCK. (if the notification
  11141.      is blockable)
  11142.  
  11143.  XTYP_RTNPKT
  11144.  
  11145.     This transaction is sent to agent applications.  hDmgData contains a
  11146.     packet to send to the agent who's handle is in the hszItem parameter.
  11147.  
  11148.  XTYP_REGISTER
  11149.  
  11150.     Another server name has just been registered with the DLL application
  11151.     name server.  hszItem is set to the application name being
  11152.     registered.  If this is NULL, an application has registered itself as
  11153.     WILD.  hDmgData is set to the application handle that registered.
  11154.     This is not blockable by CBR_BLOCK because no hConv is
  11155.     associated with it.  Only if all callbacks are disabled is this
  11156.     transaction blocked.
  11157.  
  11158.  XTYP_UNREGISTER
  11159.  
  11160.     Another server application has just unregistered a name with this
  11161.     DLL.  hszItem is set to the application name being unregistered.
  11162.     hDmgData is set to the app handle of the unregistering application.
  11163.     This is not blockable by CBR_BLOCK because no hConv is associated
  11164.     with it.  Only if all callbacks are disabled is this transaction
  11165.     blocked.
  11166.  
  11167.  XTYP_INIT_CONFIRM
  11168.  
  11169.     Sent to let a server know that a conversation on application hszItem
  11170.     and Topic hszTopic has been established on hConv.  hConv uniquely
  11171.     identifies this conversation from the server's prospective.  This
  11172.     call cannot be blocked because it is part of the DDE initiate
  11173.     sequence.  This callback is generated by the results of XTYP_INIT and
  11174.     XTYP_WILDINIT callbacks.
  11175.  
  11176.  XTYP_TERM
  11177.  
  11178.     This is a notification telling a server application that a
  11179.     conversation has been terminated.  hConv is set to identify which
  11180.     conversation was terminated.
  11181.  
  11182.  XTYP_ADVSTOP
  11183.  
  11184.     This notifies a server that an advise loop is stopping.  hszTopic,
  11185.     hszItem, and usFormat identify the advise loop within hConv.
  11186.  
  11187.  XTYP_XFERCOMPLETE
  11188.  
  11189.     This notifictaion is sent to a client when an asynchronous data
  11190.     DdeClientXfer() transaction is completed.  hDmgData is the client
  11191.     queue ID of the completed transaction.  hConv is the client
  11192.     conversation handle.
  11193.  
  11194.  XTYP_MONITOR
  11195.  
  11196.     This notifies an app registered as DMGCMD_MONITOR of DDE data that is
  11197.     being transmitted.  hDmgData contains a text string representing the
  11198.     transaction suitable for printing on a terminal, file, or window.
  11199.     Note that this monitors ALL DDE communication and may be extensive.
  11200.     This call cannot be delayed by disabled callbacks.  This transaction
  11201.     is not blockable.
  11202.  
  11203.  XTYP_ACK
  11204.  
  11205.     This notifies a server that it has received an acknowledge from data
  11206.     it has sent a client.  The hConv, topic, item, and format are set
  11207.     apropriately.  LOUSHORT(hDmgData) will contain the dde flags from the
  11208.     ack.
  11209.  
  11210.  -----XCLASS_DATA class:
  11211.  
  11212.     Transactions in this class are expected to return an HDMGDATA or 0 as
  11213.     apropriate.
  11214.  
  11215.  XTYP_PKT
  11216.  
  11217.     This transaction is sent to agent applications.  hDmgData contains a
  11218.     packet to send.  hszItem contains the agent handle to send the data
  11219.     to.  hConv is set to the associated conversation handle.  The return
  11220.     packet received from the partner agent should be returned.  This
  11221.     call is blockable.
  11222.  
  11223.     If blocked, the conversation will be unblocked and processed by
  11224.     DdeProcessPkt() when the return packet is received.  It is a good
  11225.     idea for the agent to remember the hConv parameter in case the return
  11226.     packet does not arrive within a reasonable amount of time via
  11227.     XTYP_RTNPKT.  If an agent determines that it wishes to kill a
  11228.     conversation, it should call DdeDisconnect().
  11229.  
  11230.  XTYP_REQUEST
  11231.  XTYP_ADVREQ
  11232.  
  11233.     Data is being requested from a server application.  The function
  11234.     should create a hDmgData using the DdePutData() function and
  11235.     return it.  XTYP_ADVREQ origonates from a DdePostAdvise() call
  11236.     while XTYP_REQUEST origonates from a client data request.
  11237.  
  11238.  XTYP_WILDINIT
  11239.  
  11240.     This is asking a DDE server permission to make multiple connections
  11241.     with a specific client.
  11242.  
  11243.     hszItem may be the application name the client is requesting or it
  11244.     may be NULL indicating a wild application name.  hszTopic may be the
  11245.     Topic requested or NULL indicating a wild topic.  If not NULL,
  11246.     hDmgData contains a CONVCONTEXT structure.  All other parameters are
  11247.     0 or NULL.
  11248.  
  11249.     For local initiates, (initiates with the server application itself)
  11250.     The server should return a 0 terminated (ie hszApp = hszTopic = 0)
  11251.     array of HSZPAIR structures using DdePutData() and
  11252.     DdeAddData().  Each hsz pair represents an app/topic the server
  11253.     wishes to support.  Each created conversation will result in an
  11254.     XTYP_INIT_CONFIRM notification.  If 0 is returned, no connections are
  11255.     made with the requesting client.  This call is made even if callbacks
  11256.     are disabled due the the synchronous nature of DDE initiates.  This
  11257.     callback cannot be blocked by returning CBR_BLOCK.
  11258.  
  11259.     Agent applications may also process this transaction as a
  11260.     representative initiate.  The agent is expected to package this
  11261.     transaction using DdeCreateInitPkt() and broadcast it to all
  11262.     apropriate agents along its communication channel.  It then must
  11263.     collect the return packets and for each packet and call
  11264.     DdeProcessPkt().  Representative initiates are synchronous in that
  11265.     the agent cannot return from this callback until all initiate return
  11266.     packets are returned.  Representative initiates do NOT result in any
  11267.     XTYP_INIT_CONFIRM notifications to the agent.  The agent is then free
  11268.     to process this transaction for local connections as described.
  11269.  
  11270.  -----XCLASS_BOOL class:
  11271.  
  11272.     Transactions in this class expect a BOOL return of TRUE or FALSE.
  11273.  
  11274.  XTYP_INIT
  11275.  
  11276.     This is a query asking a DDE server permission to connect to a
  11277.     specific client.  hszItem is set to the Application name.  hszTopic
  11278.     is set to the topic name.  hDmgData if not NULL, contains CONVCONTEXT
  11279.     data.  All other parameters are 0 or NULL.  A TRUE return value
  11280.     allows the Dde to start up a server on the app/topic specified.
  11281.     This will result in an XTYP_INIT_CONFIRM callback.  This call is made
  11282.     even if callbacks are disabled due the the synchronous nature of DDE
  11283.     initiates.
  11284.  
  11285.     Agent applications may process this transaction as a representative
  11286.     transaction.  The agent is expected to package this transaction using
  11287.     DdeCreateInitPkt() and broadcast it to all apropriate agents along
  11288.     its communication channel.  It then must collect the return packets
  11289.     and for each packet call DdeProcessPkt().  This will NOT result in
  11290.     any XTYP_INIT_CONFIRM notifications to the agent.  The agent is then
  11291.     free to process this transaction for local connections.
  11292.  
  11293.      A FALSE return implies no local initiate permissions are granted.
  11294.  
  11295.  XTYP_ADVSTART
  11296.  
  11297.     This transaction requests permission to start a DDE advise loop with
  11298.     a server.  The hszTopic, hszItem, and usFormat identify the advise
  11299.     loop.  If FALSE is returned, the advise loop will not be started.
  11300.  
  11301.  -----XCLASS_FLAGS Class:
  11302.  
  11303.     Transactions in this class have hDmgData set.  An application should
  11304.     use the DLL Data functions to extract the data from hDmgData.  The
  11305.     return value should be the DDE fsStatus flags the app desires to
  11306.     return to the client application.  If DDE_FACK is set, DDE_FBUSY and
  11307.     DDE_FNOTPROCESSED are ignored.
  11308.  
  11309.     The only flags the Dde expects to be returned are:
  11310.          DDE_FACK
  11311.          DDE_FBUSY
  11312.          DDE_FNOTPROCESSED
  11313.          any DDE_APPSTATUS bits
  11314.  
  11315.     All other bits will be stripped out by the Dde before sending an
  11316.     ack message.
  11317.  
  11318.     A 0 return is equivalent to DDE_NOTPROCESSED.
  11319.  
  11320.  XTYP_EXEC
  11321.  
  11322.     hDmgData contains an execute string from a client.  hConv, hszTopic,
  11323.     hszItem are set.  If the WM_DDE_EXECUTE message received had the same
  11324.     string for the itemname as for the data, hszItem will be 0L.  This
  11325.     provides for EXCEL EXECUTE compatibility without requireing the
  11326.     creation of an HSZ for the data string.  Applications are advised to
  11327.     ignore the hszItem parameter for execute transactions since newer DDE
  11328.     specifications ignore this value.
  11329.  
  11330.  XTYP_POKE
  11331.  
  11332.     Similar to XTYP_EXEC but hDmgData contains data poked to the server.
  11333.  
  11334.  XTYP_ADVDATA - advise data for a client!
  11335.  
  11336.     Note that XTYP_ADVDATA is for advise loop data intended for the
  11337.     CLIENT not the server.  If the advise loop in progress is of the
  11338.     NODATA type, hDmgData will be 0.
  11339.  
  11340.  -----Agent Transfers:
  11341.  
  11342.     A DDE agent application is one which registers itself with the
  11343.     DMGCMD_AGENT flag.  Agent applications represent any number of other
  11344.     applications across its communications channel.  Agent applications
  11345.     are only allowed to communicate locally with other non-agent
  11346.     applications.  This prevents communication loops from forming across
  11347.     communication channels.  Any number of agents may register with the
  11348.     DLL but each agent should represent a different communication
  11349.     channel, one which is orthogonal to all other agents.  It is the
  11350.     users responsability to only start up orthogonal agents.
  11351.  
  11352.     Agents are responsible for handling and updating any DDE nameservers
  11353.     associated with their communicaton channels.  Since agent
  11354.     applications can converse directly with non-agent applications, they
  11355.     can set up advise loops on the SysTopic/Topics items of local
  11356.     applications to update the nameserver for the communication channel
  11357.     if they wish to support DDE topics.  This may be impossible with some
  11358.     DDE applications which either do not support the SysTopic/Topics item
  11359.     or which have an unenumerable set of topics they support.  For
  11360.     application name servers the DdeAppNameServer() function is
  11361.     provided to give agents a local application name server from which to
  11362.     draw on.
  11363.  
  11364.     In general, an agent administers two classes of conversations.  One
  11365.     is direct conversations with itself and local non-agent applications.
  11366.     These transactions would be handled by the agent exactly like any
  11367.     non-agent application would handle them.
  11368.  
  11369.     The other class is representative conversations which the agent
  11370.     passes over its communication channel.  In general, representative
  11371.     conversation callbacks to the agent are only XTYP_PKT or XTYP_RTNPKT
  11372.     type transactions or specially handled initiate transactions.
  11373.  
  11374.     Agent applications are responsible for providing a unique ULONG agent
  11375.     handle for every agent it is communicating with on its communication
  11376.     channel.  The handle is provided by the agent whenever it calls
  11377.     DdeProcessPkt().  Agent handles need not be global to the channel
  11378.     since only the agent that created the handle will be expected to use
  11379.     it.  Agent handles should not change over the life of a conversation.
  11380.  
  11381.     Should it be necessary to allow agents to alter or convert packet
  11382.     data, the format of the packets can be documented later.
  11383.  
  11384.     To show how an agent would handle its callback function, the
  11385.     following pseudo code is offered as a model:
  11386.  
  11387.  ReceivePkt(pBits, cb, hAgentFrom)    \\ gets called when a packet arrives
  11388.  {
  11389.      hPkt = DdePutData(pBits, cb, 0, 0, 0, 0);
  11390.      if (hDmgData = ProcessPkt(hPkt, hAgentFrom))
  11391.          PassPkt(hDmgData, hAgentFrom);  \\ agent function to send pkt
  11392.  }
  11393.  
  11394.  AgentCallback(hConv, hszTopic, hszItem, usFormat, usType, hDmgData)
  11395.  {
  11396.      switch (usType) {
  11397.      case XTYP_INIT:
  11398.      case XTYP_WILDINIT:
  11399.          \\
  11400.          \\ process representative initiates
  11401.          \\
  11402.          QueryInterestedAgents(hszApp, hszTopic, pAgents);
  11403.          hDmgData = DdeCreateInitPkt(hszTopic, hszItem, hDmgData);
  11404.          BroadcastPkt(hDmgData, pAgents);
  11405.          \\
  11406.          \\ agent blocks here till all are in or timeout.
  11407.          \\ Packets get sent to ReceivePkt()
  11408.          \\
  11409.          CollectRtnPkts(pAgents);
  11410.          \\
  11411.          \\ now agent does his own processing of local inits.
  11412.          \\ retval == 0 if not interested.
  11413.          \\
  11414.          return(retval);
  11415.          break;
  11416.  
  11417.      case XTYP_RTNPKT:
  11418.          RemoveFromDeadCheckQ(hConv);
  11419.          PassPkt(hDmgData, hszItem); \\ hDmgData==Pkt, hszItem==hAgentTo
  11420.          return(0);
  11421.          break;
  11422.  
  11423.      case XTYP_PKT:
  11424.          if (FindIgnoreList(hConv) { \\ was this unblocked due to no rtn pkt?
  11425.              RemoveFromIgnoreList(hConv);
  11426.              return(0);  \\ rtn pkt failure.
  11427.          }
  11428.          if (!PassPkt(hDmgData, hszItem))  \\ hDmgData==Pkt, hszItem==hAgentTo
  11429.              return(0);  \\ packet send failure.
  11430.          AddToDeadCheckQ(hConv, timenow());
  11431.          return(CBR_BLOCK);  \\ will be unblocked and handled by ProcessPkt()
  11432.          break;
  11433.  
  11434.      case XTYP_REGISTER:
  11435.      case XTYP_UNREGISTER:
  11436.          \\
  11437.          \\ agent updates its communications name server.
  11438.          \\
  11439.          return(0);
  11440.          break;
  11441.  
  11442.      default:
  11443.          \\
  11444.          \\ the rest would reference local conversatoins that the agent
  11445.          \\ is maintaining.
  11446.          \\
  11447.          break;
  11448.      }
  11449.  }
  11450.  
  11451.  UnblockDeadTransaction(hConv) \\ called when no rtn pkt for hConv has been
  11452.                                \\ received for a long time.
  11453.  {
  11454.      RemoveFromDeadCheckQ(hConv);
  11455.      AddToIgnoreList(hConv);
  11456.      DdeEnableCallback(CBK_ENABLE, hConv);
  11457.  }
  11458.  
  11459.  \* PUBDOC END */
  11460.  
  11461.  
  11462.  /***************************** Public  Function ****************************\
  11463.  * PUBDOC START
  11464.  * USHORT EXPENTRY DdeInitialize(pfnCallback, afCmd, ulRes)
  11465.  * PFNCALLBACK pfnCallback;  // address to application callback function
  11466.  * ULONG afCmd;              // registration command flags
  11467.  * ULONG ulRes;              // currently reserved, must be 0L.
  11468.  *
  11469.  *     This API is used to initialize the DDEML for an application thread.
  11470.  *
  11471.  *     afCmd - is a set of DMGCMD_ flags for special initialization instructio
  11472.  *
  11473.  *     DMGCMD_AGENT
  11474.  *         The registering application represents more than one DDE applicatio
  11475.  *         Agents are never allowed to establish a conversation with
  11476.  *         another agent.  See Agent Transactions.
  11477.  *
  11478.  *     DMGCMD_MONITOR
  11479.  *
  11480.  *         This defines the registered application as a DDE transaction
  11481.  *         monitor.  This is primarily used for debugging DDE
  11482.  *         applications.  A monitoring application will have its Callback
  11483.  *         function called every time a DDE message is sent.
  11484.  *
  11485.  *         This flag is exclusive of all others.  No other flags should be
  11486.  *         or'ed in with this one.
  11487.  *
  11488.  *    DMGCMD_CLIENTONLY
  11489.  *        This should be specified when the application only intends to
  11490.  *        be a DDE client.  This reduces the resource consumption of the DLL.
  11491.  *
  11492.  *     Registration is on a per-thread basis.  Thus a multi-threaded applicati
  11493.  *     could register several threads as seperate DDE entities.
  11494.  *
  11495.  *     returns any applicable DMGERR_ error code or 0 on success.
  11496.  *
  11497.  *     Most other DLL APIs will fail if the calling thread has not called this
  11498.  *
  11499.  * PUBDOC END
  11500.  *
  11501.  * Registration causes the following windows to be created:
  11502.  *
  11503.  * HWND_OBJECT
  11504.  *   hwndDmg(s)
  11505.  *       hwndClient(s)
  11506.  *   hwndTopicServer(s)
  11507.  *       hwndServer(s)
  11508.  *   hwndMonitor(s)
  11509.  * HWND_DESKTOP
  11510.  *   hwndFrame(s)
  11511.  *
  11512.  *   See api.doc file for usage info.
  11513.  *
  11514.  * History:
  11515.  *   Created     12/14/88    Sanfords
  11516.  \***************************************************************************/
  11517.  USHORT EXPENTRY DdeInitialize(pfnCallback, afCmd, ulRes)
  11518.  PFNCALLBACK pfnCallback;
  11519.  ULONG afCmd;
  11520.  ULONG ulRes;
  11521.  {
  11522.      if (ulRes != 0L || CheckSel(SELECTOROF(pfnCallback)) == 0)
  11523.          return(DMGERR_INVALIDPARAMETER);
  11524.  
  11525.      return(Register(pfnCallback, afCmd, ulRes, FALSE));
  11526.  }
  11527.  
  11528.  
  11529.  
  11530.  USHORT EXPENTRY Register(pfnCallback, afCmd, ulRes, f32bit)
  11531.  PFNCALLBACK pfnCallback;
  11532.  ULONG afCmd;
  11533.  ULONG ulRes;
  11534.  BOOL f32bit;    /* set if calling app is a 32bit app. */
  11535.  {
  11536.      BOOL        fInit;
  11537.      PAPPINFO    pai = 0L, paiT;
  11538.      PIDINFO     pidInfo;
  11539.      USHORT      usRet = DMGERR_PMWIN_ERROR;
  11540.      ULONG       ctlFlags;
  11541.      CLASSINFO   ci;
  11542.      USHORT      cb;
  11543.  
  11544.      UNUSED ulRes;
  11545.  
  11546.      SemEnter();
  11547.      if (fInit = (hheapDmg == 0L)) {
  11548.          /*
  11549.           * First time only
  11550.           */
  11551.          syscc.codepage = syscc.country = 0;
  11552.          DosGetCtryInfo(sizeof(COUNTRYCODE), &syscc, (PCOUNTRYINFO)&syscc, &cb
  11553.          if (DosGetHugeShift(&usHugeShift))
  11554.              goto Abort;
  11555.          usHugeAdd = (1 << usHugeShift) - 1;
  11556.          if (!(hheapDmg = MyCreateHeap(0, 4096, 0, 0, 0, HEAPFLAGS)))
  11557.              goto Abort;
  11558.          if (!WinQueryClassInfo(DMGHAB, WC_FRAME, &ci))
  11559.              goto Abort;
  11560.          lpfnFrameWndProc = ci.pfnWindowProc;
  11561.          if (!AddAtomTable(TRUE))
  11562.              goto Abort;
  11563.      } else {
  11564.  
  11565.          if ((pai = GetCurrentAppInfo(FALSE)) != NULL) {
  11566.              /*
  11567.               * re-registration
  11568.               */
  11569.              return(DMGERR_DLL_USAGE);
  11570.          }
  11571.  
  11572.          /*
  11573.           * share the main heap with this process.
  11574.           */
  11575.          if (DosGetSeg(SELECTOROF(hheapDmg))) {
  11576.              SemLeave();
  11577.              return(DMGERR_PMWIN_ERROR);
  11578.          }
  11579.      }
  11580.  
  11581.  
  11582.      if (DosGetPID(&pidInfo))
  11583.          goto Abort;
  11584.  
  11585.      if (!(pai = (PAPPINFO)FarAllocMem(hheapDmg, sizeof(APPINFO))))
  11586.          goto Abort;
  11587.  
  11588.      if (!(pai->hheapApp = MyCreateHeap(0, 4096, 0, 0, 0, HEAPFLAGS))) {
  11589.          FarFreeMem(hheapDmg, pai, sizeof(APPINFO));
  11590.          pai = 0L;
  11591.          goto Abort;
  11592.      }
  11593.  
  11594.      pai->pAppNamePile = NULL;   /* responds to nothing */
  11595.      pai->pSvrTopicList = CreateLst(pai->hheapApp, sizeof(HWNDHSZLI));
  11596.      pai->pHDataPile = CreatePile(pai->hheapApp, sizeof(HDMGDATA), 8);
  11597.      pai->afCmd = (USHORT)afCmd | (f32bit ? DMGCMD_32BIT : 0);
  11598.      pai->hwndDmg =
  11599.      pai->hwndFrame =
  11600.      pai->hwndMonitor =
  11601.      pai->hwndTimer = 0;
  11602.      pai->pid = pidInfo.pid;
  11603.      pai->tid = pidInfo.tid;
  11604.      pai->pfnCallback = pfnCallback;
  11605.      pai->cInCallback = 0;
  11606.      pai->LastError = DMGERR_NO_ERROR;
  11607.      pai->fEnableCB = TRUE;
  11608.      pai->plstCB = CreateLst(pai->hheapApp, sizeof(CBLI));
  11609.      pai->plstCBExceptions = NULL;
  11610.  
  11611.      /*
  11612.       * make nextThread link.
  11613.       */
  11614.      paiT = pAppInfoList;
  11615.      while (paiT && paiT->pid != pai->pid) {
  11616.          paiT = paiT->next;
  11617.      }
  11618.      pai->nextThread = paiT; /* paiT is NULL or of the same process */
  11619.  
  11620.      if (paiT) {
  11621.          while (paiT->nextThread->tid != pai->nextThread->tid) {
  11622.              paiT = paiT->nextThread;
  11623.          }
  11624.          paiT->nextThread = pai;
  11625.      } else {
  11626.          /*
  11627.           * We must reregister each class for each process that invokes this
  11628.           * DLL because we can't register public classes unless we are the
  11629.           * shell.
  11630.           * Since pai->nextThread is NULL, this is a new process.
  11631.           */
  11632.          WinRegisterClass(0, SZCLIENTCLASS, ClientWndProc, 0L, 4);
  11633.          WinRegisterClass(0, SZSERVERCLASS, ServerWndProc, 0L, 4);
  11634.          WinRegisterClass(0, SZDMGCLASS, DmgWndProc, 0L, 4);
  11635.          WinRegisterClass(0, SZDEFCLASS, WinDefWindowProc, 0L, 4);
  11636.      }
  11637.  
  11638.      pai->next = pAppInfoList;
  11639.      pAppInfoList = pai;
  11640.  
  11641.      if ((pai->hwndDmg = WinCreateWindow(HWND_OBJECT, SZDMGCLASS, "", 0L,
  11642.              0, 0, 0, 0, (HWND)NULL, HWND_BOTTOM, WID_APPROOT, 0L, 0L)) == 0L)
  11643.          goto Abort;
  11644.      }
  11645.  
  11646.      if (pai->afCmd & DMGCMD_MONITOR) {
  11647.          WinRegisterClass(0, SZMONITORCLASS, MonitorWndProc, 0L, 4);
  11648.          if ((pai->hwndMonitor = WinCreateWindow(HWND_OBJECT, SZMONITORCLASS,
  11649.                  0L, 0, 0, 0, 0, (HWND)NULL, HWND_BOTTOM, WID_MONITOR, 0L, 0L)
  11650.                  == 0L) {
  11651.              goto Abort;
  11652.          }
  11653.          if (++cMonitor) {
  11654.              WinSetHook(DMGHAB, NULL, HK_INPUT, (PFN)DdePostHookProc, hmodDmg)
  11655.              WinSetHook(DMGHAB, NULL, HK_SENDMSG, (PFN)DdeSendHookProc, hmodDm
  11656.          }
  11657.      }
  11658.  
  11659.      /*
  11660.       * create an invisible top-level frame for initiates. (if server ok)
  11661.       */
  11662.      usRet = DMGERR_PMWIN_ERROR;
  11663.      if (!(afCmd & DMGCMD_CLIENTONLY)) {
  11664.          ctlFlags = 0;
  11665.          if ((pai->hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &ctlFlags,
  11666.                  (PSZ)NULL, "", 0L, (HMODULE)NULL, 0, (PHWND)NULL)) == (HWND)N
  11667.              goto Abort;
  11668.          WinSubclassWindow(pai->hwndFrame, subframeWndProc);
  11669.      }
  11670.  
  11671.      DosExitList(EXLST_ADD, (PFNEXITLIST)ExlstAbort);
  11672.  
  11673.      SemLeave();
  11674.  
  11675.      return(DMGERR_NO_ERROR);
  11676.  
  11677.  Abort:
  11678.      SemLeave();
  11679.  
  11680.      if (pai)
  11681.          DdeUninitialize();
  11682.      else if (fInit && hheapDmg)
  11683.          hheapDmg = MyDestroyHeap(hheapDmg);
  11684.      return(usRet);
  11685.  }
  11686.  
  11687.  
  11688.  /***************************** Public  Function ****************************\
  11689.  * PUBDOC START
  11690.  * BOOL EXPENTRY DdeUninitialize(void);
  11691.  *     This uninitializes an application thread from the DDEML.
  11692.  *     All DLL resources associated with the application are destroyed.
  11693.  *     Most other APIs will fail if called after this API by the same thread.
  11694.  *
  11695.  * PUBDOC END
  11696.  *
  11697.  * History:
  11698.  *   Created     12/14/88    Sanfords
  11699.  \***************************************************************************/
  11700.  BOOL EXPENTRY DdeUninitialize()
  11701.  {
  11702.      PAPPINFO pai, paiT;
  11703.      PMYDDES pmyddes;
  11704.      PIDINFO pi;
  11705.  
  11706.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  11707.          return(FALSE);
  11708.  
  11709.      DosExitList(EXLST_REMOVE, (PFNEXITLIST)ExlstAbort);
  11710.  
  11711.      /*
  11712.       * get us out of the semaphore!
  11713.       * !!! NOTE: semaphore tid id -1 during exitlist processing!
  11714.       */
  11715.      DosGetPID(&pi);
  11716.      if (FSRSemDmg.cUsage > 0 && FSRSemDmg.pid == pi.pid &&
  11717.              (FSRSemDmg.tid == pi.tid || FSRSemDmg.tid == -1)) {
  11718.          while (FSRSemDmg.cUsage) {
  11719.              SemLeave();
  11720.          }
  11721.      }
  11722.  
  11723.      if (pai->hwndTimer)
  11724.          WinSendMsg(pai->hwndTimer, WM_TIMER, MPFROMSHORT(TID_ABORT), 0L);
  11725.  
  11726.      if (pai->hwndMonitor) {
  11727.          DestroyWindow(pai->hwndMonitor);
  11728.          if (!--cMonitor) {
  11729.              WinReleaseHook(DMGHAB, NULL, HK_INPUT, (PFN)DdePostHookProc, hmod
  11730.              WinReleaseHook(DMGHAB, NULL, HK_SENDMSG, (PFN)DdeSendHookProc, hm
  11731.          }
  11732.      }
  11733.  
  11734.      /*
  11735.       * inform others of DeRegistration
  11736.       */
  11737.      if (pai->pAppNamePile != NULL)
  11738.          DdeAppNameServer(NULL, ANS_UNREGISTER);
  11739.  
  11740.      UnlinkAppInfo(pai);
  11741.  
  11742.      DestroyWindow(pai->hwndDmg);
  11743.      DestroyWindow(pai->hwndFrame);
  11744.      DestroyHwndHszList(pai->pSvrTopicList);
  11745.      while (PopPileSubitem(pai->pHDataPile, (PBYTE)&pmyddes)) {
  11746.          if (CheckSel(SELECTOROF(pmyddes)) > sizeof(MYDDES) &&
  11747.                  pmyddes->magic == MYDDESMAGIC &&
  11748.                  pmyddes->pai == pai) {
  11749.              pmyddes->fs &= ~HDATA_APPOWNED;
  11750.          }
  11751.          FreeData(pmyddes, pai);
  11752.      }
  11753.      DestroyPile(pai->pHDataPile);
  11754.      if (pai->nextThread) {
  11755.          paiT = pai;
  11756.          while (paiT->nextThread != pai) {
  11757.              paiT = paiT->nextThread;
  11758.          }
  11759.          paiT->nextThread = pai->nextThread;
  11760.          if (paiT->nextThread == paiT) {
  11761.              paiT->nextThread = NULL;
  11762.          }
  11763.      }
  11764.      MyDestroyHeap(pai->hheapApp);
  11765.  
  11766.      DestroyPile(pai->pAppNamePile);
  11767.      FarFreeMem(hheapDmg, (PBYTE)pai, sizeof(APPINFO));
  11768.  
  11769.      if (pAppInfoList == NULL) {     /* last guy out? - turn the lights out. *
  11770.          while (cAtbls--)
  11771.              WinDestroyAtomTable(aAtbls[cAtbls]);
  11772.          hheapDmg = MyDestroyHeap(hheapDmg);
  11773.      } else
  11774.          DosFreeSeg(SELECTOROF(hheapDmg));
  11775.  
  11776.      SemCheckOut();
  11777.  
  11778.      return(TRUE);
  11779.  }
  11780.  
  11781.  
  11782.  
  11783.  /***************************** Public  Function ****************************\
  11784.  * PUBDOC START
  11785.  * HCONVLIST EXPENTRY DdeBeginEnumServers(
  11786.  * HSZ hszAppName,    // app name to connect to, NULL is wild.
  11787.  * HSZ hszTopic,      // topic name to connect to, NULL is wild.
  11788.  * HCONV hConvList,   // previous hConvList for reenumeration, NULL for initia
  11789.  * PCONVCONTEXT pCC,  // language info or NULL for system default.
  11790.  * HAPP hApp);        // target application handle or NULL for broadcast init.
  11791.  *
  11792.  *   hszAppName - the DDE application name to connect to - may be 0 for wild.
  11793.  *   hszTopic - the DDE topic name to connect to - may be 0 for wild.
  11794.  *   hConvList - The conversation list handle to use for reenumeration.
  11795.  *       If this is 0, a new hConvList is created.
  11796.  *   pCC - pointer to CONVCONTEXT structure which provides conversation
  11797.  *       information needed for international support.  All DDEFMT_TEXT
  11798.  *       strings within any conversation started by this call should use
  11799.  *       the codepage referenced in this structure.
  11800.  *       If NULL is given, the current system values are used.
  11801.  *   hApp - if not NULL, this directs initiates to only be sent to hApp.
  11802.  *
  11803.  *       This routine connects all available conversations on the given
  11804.  *       app/topic pair.  Hsz values of 0 indicate wild names.  On reenumerati
  11805.  *       old hConv's are kept and any new ones created are added to the
  11806.  *       list.  Duplicate connections are avoided where possible.  A
  11807.  *       duplicate connection is one which is to the same process and
  11808.  *       thread on the same application/topic names.  If hApp is provided,
  11809.  *       initiates are given only to that application.
  11810.  *       Reenumeration is primarily intended as a response
  11811.  *       to registration of a new app name to the system.  Reenumeration
  11812.  *       also removes any terminated conversations from the list.
  11813.  *
  11814.  *   returns NULL on failure, hConvList on success.
  11815.  *
  11816.  * PUBDOC END
  11817.  *
  11818.  * History:
  11819.  *   Created     12/14/88    Sanfords
  11820.  \***************************************************************************/
  11821.  HCONVLIST EXPENTRY DdeBeginEnumServers(hszAppName, hszTopic, hConvList,
  11822.          pCC, hApp)
  11823.  HSZ hszAppName;
  11824.  HSZ hszTopic;
  11825.  HWND hConvList;
  11826.  PCONVCONTEXT pCC;
  11827.  HAPP hApp;
  11828.  {
  11829.      PAPPINFO            pai;
  11830.      HCONV               hConv, hConvNext, hConvNew;
  11831.      HCONVLIST           hConvListNew;
  11832.      PCLIENTINFO         pciOld, pciNew;
  11833.      PID                 pidOld, pidNew;
  11834.      TID                 tidOld, tidNew;
  11835.  
  11836.      if ((pai = GetCurrentAppInfo(TRUE)) == 0)
  11837.          return(0);
  11838.  
  11839.      /*
  11840.       * destroy any dead old clients
  11841.       */
  11842.      if (hConvList) {
  11843.          hConv = WinQueryWindow(hConvList, QW_TOP, FALSE);
  11844.          while (hConv != NULL) {
  11845.              hConvNext = WinQueryWindow(hConv, QW_NEXT, FALSE);
  11846.              if (!((USHORT)WinSendMsg(hConv, UM_QUERY, MPFROMSHORT(Q_STATUS),
  11847.                      ST_CONNECTED))
  11848.                  WinDestroyWindow(hConv);
  11849.              hConv = hConvNext;
  11850.          }
  11851.      }
  11852.  
  11853.      if ((hConvListNew = WinCreateWindow(pai->hwndDmg, SZDEFCLASS, "", 0L,
  11854.              0, 0, 0, 0, (HWND)NULL, HWND_BOTTOM, WID_CLROOT, 0L, 0L)) == NULL
  11855.          pai->LastError = DMGERR_PMWIN_ERROR;
  11856.          return(0L);
  11857.      }
  11858.  
  11859.      hConvNew = GetDDEClientWindow(hConvListNew, (HWND)hApp, NULL, hszAppName,
  11860.              hszTopic, pCC);
  11861.  
  11862.      /*
  11863.       * If no new hConvs created, quit now.
  11864.       */
  11865.      if (hConvNew == NULL) {
  11866.          if (hConvList && WinQueryWindow(hConvList, QW_TOP, FALSE) == NULL) {
  11867.              DestroyWindow(hConvList);
  11868.              hConvList = NULL;
  11869.          }
  11870.          if (hConvList == NULL)
  11871.              pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  11872.          return(hConvList);
  11873.      }
  11874.  
  11875.      /*
  11876.       * remove any new ones that duplicate old existing ones
  11877.       */
  11878.      if (hConvList && (hConv = WinQueryWindow(hConvList, QW_TOP, FALSE))) {
  11879.          while (hConv) {
  11880.              hConvNext = WinQueryWindow(hConv, QW_NEXT, FALSE);
  11881.              pciOld = (PCLIENTINFO)WinQueryWindowULong(hConv, QWL_USER);
  11882.              if (!WinIsWindow(DMGHAB, pciOld->ci.hwndPartner)) {
  11883.                  WinDestroyWindow(hConv);
  11884.                  hConv = hConvNext;
  11885.                  continue;
  11886.              }
  11887.              WinQueryWindowProcess(pciOld->ci.hwndPartner, &pidOld, &tidOld);
  11888.              /*
  11889.               * destroy any new clients that are duplicates of the old ones.
  11890.               */
  11891.              hConvNew = WinQueryWindow(hConvListNew, QW_TOP, FALSE);
  11892.              while (hConvNew) {
  11893.                  hConvNext = WinQueryWindow(hConvNew, QW_NEXT, FALSE);
  11894.                  pciNew = (PCLIENTINFO)WinQueryWindowULong(hConvNew, QWL_USER)
  11895.                  WinQueryWindowProcess(pciNew->ci.hwndPartner, &pidNew, &tidNe
  11896.                  if (pciOld->ci.hszServerApp == pciNew->ci.hszServerApp &&
  11897.                          pciOld->ci.hszTopic == pciNew->ci.hszTopic &&
  11898.                          pidOld == pidNew &&
  11899.                          tidOld == tidNew) {
  11900.                      /*
  11901.                       * assume same app, same topic, same process, same thread
  11902.                       * is a duplicate.
  11903.                       */
  11904.                      WinDestroyWindow(hConvNew);
  11905.                  }
  11906.                  hConvNew = hConvNext;
  11907.              }
  11908.              /*
  11909.               * move the unique old client to the new list
  11910.               */
  11911.              WinSetParent(hConv, hConvListNew, FALSE);
  11912.              hConv = hConvNext;
  11913.          }
  11914.          WinDestroyWindow(hConvList);
  11915.      }
  11916.  
  11917.      /*
  11918.       * If none are left, fail because no conversations were established.
  11919.       */
  11920.      if (WinQueryWindow(hConvListNew, QW_TOP, FALSE) == NULL) {
  11921.          DestroyWindow(hConvListNew);
  11922.          pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  11923.          return(NULL);
  11924.      } else {
  11925.          return(hConvListNew);
  11926.      }
  11927.  }
  11928.  
  11929.  
  11930.  
  11931.  /***************************** Public  Function ****************************\
  11932.  * PUBDOC START
  11933.  * HCONV EXPENTRY DdeGetNextServer(
  11934.  * HCONVLIST hConvList,  // conversation list being traversed
  11935.  * HCONV hConvPrev)      // previous conversation extracted or NULL for first
  11936.  *
  11937.  * hConvList - handle of conversation list returned by DdeBeginEnumServers().
  11938.  * hConvPrev - previous hConv returned by this API or 0 to start from the top
  11939.  *   of hConvList.
  11940.  *
  11941.  * This API returns the next conversation handle associated with hConvList.
  11942.  * A 0 is returned if hConvPrev was the last conversation or if hConvList
  11943.  * has no active conversations within it.
  11944.  *
  11945.  * PUBDOC END
  11946.  *
  11947.  * History:
  11948.  *   Created     12/14/88    Sanfords
  11949.  \***************************************************************************/
  11950.  HCONV EXPENTRY DdeGetNextServer(hConvList, hConvPrev)
  11951.  HCONVLIST hConvList;
  11952.  HCONV hConvPrev;
  11953.  {
  11954.      if (!WinIsWindow(DMGHAB, hConvList))
  11955.          return(NULL);
  11956.      if (hConvPrev == NULL)
  11957.          return(WinQueryWindow(hConvList, QW_TOP, FALSE));
  11958.      else
  11959.          return(WinQueryWindow(hConvPrev, QW_NEXT, FALSE));
  11960.  }
  11961.  
  11962.  
  11963.  
  11964.  
  11965.  /***************************** Public  Function ****************************\
  11966.  * PUBDOC START
  11967.  * BOOL EXPENTRY DdeEndEnumServers(hConvList)
  11968.  * HCONVLIST hConvList;  // conversation list to destroy.
  11969.  *
  11970.  * hConvList - a conversation list handle returned by DdeBeginEnumServers().
  11971.  *
  11972.  * This API destroys hConvList and terminates all conversations associated
  11973.  * with it.  If an application wishes to save selected conversations within
  11974.  * hConvList, it should call DdeDisconnect() on all hConv's it does not
  11975.  * want to use and not call this API.
  11976.  *
  11977.  * PUBDOC END
  11978.  * History:
  11979.  *   Created     12/14/88    Sanfords
  11980.  \***************************************************************************/
  11981.  BOOL EXPENTRY DdeEndEnumServers(hConvList)
  11982.  HCONVLIST hConvList;
  11983.  {
  11984.      PAPPINFO pai;
  11985.      HCONV hConv, hConvNext;
  11986.  
  11987.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  11988.          return(FALSE);
  11989.      if (WinIsWindow(DMGHAB, hConvList)) {
  11990.          hConv = WinQueryWindow(hConvList, QW_TOP, FALSE);
  11991.          while (hConv != NULL) {
  11992.              hConvNext = WinQueryWindow(hConv, QW_NEXT, FALSE);
  11993.              DestroyWindow(hConv);
  11994.              hConv = hConvNext;
  11995.          }
  11996.          DestroyWindow(hConvList);
  11997.      }
  11998.      return(TRUE);
  11999.  }
  12000.  
  12001.  
  12002.  
  12003.  /***************************** Public  Function ****************************\
  12004.  * PUBDOC START
  12005.  * HCONV EXPENTRY DdeConnect(hszAppName, hszTopic, pCC, hApp)
  12006.  * HSZ hszAppName;   // app name to connect to, NULL is wild.
  12007.  * HSZ hszTopic;     // topic name to connect to, NULL is wild.
  12008.  * PCONVCONTEXT pCC; // language information or NULL for sys default.
  12009.  * HAPP hApp;        // target application or NULL for broadcast.
  12010.  *
  12011.  * hszAppName - DDE application name to connect to.
  12012.  * hszTopic - DDE Topic name to connect to.
  12013.  * pCC - CONVCONTEXT information pertinant to this conversation.
  12014.  *       If NULL, the current system information is used.
  12015.  * hApp - if not NULL, directs connection to a specific app.
  12016.  *
  12017.  * returns - the conversation handle of the connected conversation or 0 on err
  12018.  *
  12019.  * This function allows the simpler aproach of allowing a client to
  12020.  * talk to the first server it finds on a topic.  It is most efficient when
  12021.  * an hApp is provided.
  12022.  *
  12023.  * PUBDOC END
  12024.  *
  12025.  * History:
  12026.  *   Created     12/16/88    Sanfords
  12027.  \***************************************************************************/
  12028.  HCONV EXPENTRY DdeConnect(hszAppName, hszTopic, pCC, hApp)
  12029.  HSZ hszAppName;
  12030.  HSZ hszTopic;
  12031.  PCONVCONTEXT pCC;
  12032.  HAPP hApp;
  12033.  {
  12034.      PAPPINFO pai;
  12035.      HCONV hConv;
  12036.  
  12037.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  12038.          return(0);
  12039.  
  12040.      hConv = GetDDEClientWindow(pai->hwndDmg, NULL, (HWND)hApp, hszAppName,
  12041.              hszTopic, pCC);
  12042.  
  12043.      if (hConv == 0)
  12044.          pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  12045.  
  12046.      return(hConv);
  12047.  }
  12048.  
  12049.  
  12050.  
  12051.  /***************************** Public  Function ****************************\
  12052.  * PUBDOC START
  12053.  * BOOL EXPENTRY DdeDisconnect(hConv)
  12054.  * hConv; // conversation handle of conversation to terminate.
  12055.  *
  12056.  * This API terminates a conversation started by either DdeConnect() or
  12057.  * DdeBeginEnumServers().  hConv becomes invalid after this call.
  12058.  *
  12059.  * If hConv is a server conversation, any transactions for that conversation
  12060.  * found on the server callback queue will be deleted prior to terminating
  12061.  * the conversation.
  12062.  *
  12063.  * If hConv is a client conversation, any transactions on the Client Queue
  12064.  * are purged before termination.
  12065.  *
  12066.  * Note that client conversations that are terminated from the server end
  12067.  * go into a dormant state but are still available so that DdeQueryConvInfo()
  12068.  * can be used to determine why a conversation is not working.
  12069.  * Server conversations will destroy themselves if terminated from a client.
  12070.  *
  12071.  * returns fSuccess
  12072.  *
  12073.  * PUBDOC END
  12074.  * History:
  12075.  *   Created     12/16/88    Sanfords
  12076.  \***************************************************************************/
  12077.  BOOL EXPENTRY DdeDisconnect(hConv)
  12078.  HCONV hConv;
  12079.  {
  12080.      PAPPINFO pai;
  12081.  
  12082.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  12083.          return(FALSE);
  12084.  
  12085.      if (!WinIsWindow(DMGHAB, hConv)) {
  12086.          pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  12087.          return(FALSE);
  12088.      }
  12089.      SemCheckOut();
  12090.      return((BOOL)WinSendMsg(hConv, UMCL_TERMINATE, 0L, 0L));
  12091.  }
  12092.  
  12093.  
  12094.  
  12095.  /***************************** Public  Function ****************************\
  12096.  * PUBDOC START
  12097.  * BOOL EXPENTRY DdeQueryConvInfo(hConv, pConvInfo, idXfer)
  12098.  * HCONV hConv;          // conversation hand to get info on.
  12099.  * PCONVINFO pConvInfo;  // structure to hold info.
  12100.  * ULONG idXfer;         // transaction ID if async, QID_SYNC if not.
  12101.  *
  12102.  * hConv - conversation handle of a conversation to query.
  12103.  * pConvInfo - pointer to CONVINFO structure.
  12104.  * idXfer - Should be a QID_ constant or an ID returned from DdeCheckQueue().
  12105.  *       if id is QID_SYNC, then the synchronous conversation state is returne
  12106.  *
  12107.  * returns - fSuccess.  The CONVINFO structure is filled in with the
  12108.  *     conversation's status on success.
  12109.  *
  12110.  * Note that a client conversation may have several transactions in progress
  12111.  * at the same time.  idXfer is used to choose which transaction to refer to.
  12112.  *
  12113.  * hConv may be a client or server conversation handle.  Server conversation
  12114.  * handles ignore idXfer.
  12115.  *
  12116.  * PUBDOC END
  12117.  *
  12118.  * History:
  12119.  *   Created     12/14/88    Sanfords
  12120.  \***************************************************************************/
  12121.  BOOL EXPENTRY DdeQueryConvInfo(hConv, pConvInfo, idXfer)
  12122.  HCONV hConv;
  12123.  PCONVINFO pConvInfo;
  12124.  ULONG idXfer;
  12125.  {
  12126.      PCLIENTINFO pci;
  12127.      PAPPINFO pai;
  12128.      PXADATA pxad;
  12129.      PCQDATA pqd;
  12130.      BOOL fClient;
  12131.  
  12132.      if ((pai = GetCurrentAppInfo(FALSE)) == 0)
  12133.          return(FALSE);
  12134.  
  12135.      SemCheckOut();
  12136.  
  12137.      /*
  12138.       * note that pci may actually be a psi if fClient is false.  Since
  12139.       * the common info portions are identical, we don't care except
  12140.       * where data is extracted from non-common portions.
  12141.       */
  12142.      if (!WinIsWindow(DMGHAB, hConv) ||
  12143.              !(pci = (PCLIENTINFO)WinSendMsg(hConv, UM_QUERY, (MPARAM)Q_ALL, 0
  12144.              !WinIsWindow(DMGHAB, pci->ci.hwndPartner)) {
  12145.          pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  12146.          return(FALSE);
  12147.      }
  12148.  
  12149.      fClient = (BOOL)WinSendMsg(hConv, UM_QUERY, (MPARAM)Q_CLIENT, 0L);
  12150.  
  12151.      if (idXfer == QID_SYNC || !fClient) {
  12152.          pxad = &pci->ci.xad;
  12153.      } else {
  12154.          if (pci->pQ != NULL &&
  12155.                  (pqd = (PCQDATA)Findqi(pci->pQ, idXfer))) {
  12156.              pxad = &pqd->xad;
  12157.          } else {
  12158.              pai->LastError = DMGERR_UNFOUND_QUEUE_ID;
  12159.              return(FALSE);
  12160.          }
  12161.      }
  12162.      SemEnter();
  12163.      pConvInfo->cb = sizeof(CONVINFO);
  12164.      pConvInfo->hConvPartner = IsDdeWindow(pci->ci.hwndPartner);
  12165.      pConvInfo->hszAppName = pci->ci.hszServerApp;
  12166.      pConvInfo->hszAppPartner = fClient ? pci->ci.hszServerApp : 0;
  12167.      pConvInfo->hszTopic = pci->ci.hszTopic;
  12168.      pConvInfo->hAgent = pci->ci.hAgent;
  12169.      pConvInfo->hApp = pci->ci.hwndFrame;
  12170.      if (fClient) {
  12171.          pConvInfo->hszItem = pxad->pXferInfo->hszItem;
  12172.          pConvInfo->usFmt = pxad->pXferInfo->usFmt;
  12173.          pConvInfo->usType = pxad->pXferInfo->usType;
  12174.          pConvInfo->usConvst = pxad->state;
  12175.          pConvInfo->LastError = pxad->LastError;
  12176.      } else {
  12177.          pConvInfo->hszItem = NULL;
  12178.          pConvInfo->usFmt = 0;
  12179.          pConvInfo->usType = 0;
  12180.          pConvInfo->usConvst = pci->ci.xad.state;
  12181.          pConvInfo->LastError = pci->ci.pai->LastError;
  12182.      }
  12183.      pConvInfo->usStatus = pci->ci.fs;
  12184.      pConvInfo->fsContext = pci->ci.cc.fsContext;
  12185.      pConvInfo->idCountry = pci->ci.cc.idCountry;
  12186.      pConvInfo->usCodepage = pci->ci.cc.usCodepage;
  12187.      SemLeave();
  12188.      return(TRUE);
  12189.  }
  12190.  
  12191.  
  12192.  
  12193.  /***************************** Public  Function ****************************\
  12194.  * PUBDOC START
  12195.  * BOOL EXPENTRY DdePostAdvise(hszTopic, hszItem)
  12196.  * HSZ hszTopic;     // topic of changed data, NULL is all topics
  12197.  * HSZ hszItem;      // item of changed data, NULL is all items
  12198.  *
  12199.  * Causes any clients who have advise loops running on the topic/item name
  12200.  * specified to receive the apropriate data messages they require.
  12201.  *
  12202.  * This should be called by a server application anytime data associated with
  12203.  * a particular topic/item changes.  This call results in XTYP_ADVREQ
  12204.  * callbacks being generated.
  12205.  *
  12206.  * hszTopic and/or hszItem may be NULL if all topics or items are to be update
  12207.  * This will result in callbacks for all active advise loops that fit the
  12208.  * hszTopic/hszItem pair.
  12209.  *
  12210.  * The API is intended for SERVERS only!
  12211.  *
  12212.  * PUBDOC END
  12213.  * History:
  12214.  *   Created     12/16/88    Sanfords
  12215.  \***************************************************************************/
  12216.  BOOL EXPENTRY DdePostAdvise(hszTopic, hszItem)
  12217.  HSZ hszTopic;
  12218.  HSZ hszItem;
  12219.  {
  12220.      PAPPINFO pai;
  12221.      HWND hwndTopic;
  12222.      HWND hwndSvr;
  12223.  
  12224.      // LATER - add wild hsz support
  12225.  
  12226.      if (((pai = GetCurrentAppInfo(TRUE)) == 0))
  12227.          return(FALSE);
  12228.  
  12229.      if (pai->afCmd & DMGCMD_CLIENTONLY) {
  12230.          pai->LastError = DMGERR_DLL_USAGE;
  12231.          return(FALSE);
  12232.      }
  12233.  
  12234.      if ((hwndTopic = HwndFromHsz((HSZ)hszTopic, pai->pSvrTopicList)) == 0)
  12235.          return(TRUE);
  12236.  
  12237.      hwndSvr = WinQueryWindow(hwndTopic, QW_TOP, FALSE);
  12238.      while (hwndSvr) {
  12239.          WinPostMsg(hwndSvr, UMSR_POSTADVISE, MPFROMSHORT(hszItem), 0L);
  12240.          hwndSvr = WinQueryWindow(hwndSvr, QW_NEXT, FALSE);
  12241.      }
  12242.  
  12243.      return(TRUE);
  12244.  }
  12245.  
  12246.  
  12247.  /***************************** Public  Function ****************************\
  12248.  * PUBDOC START
  12249.  * HDMGDATA EXPENTRY DdeClientXfer(pSrc, cb, hConv, hszItem, usFmt,
  12250.  *         usType, ulTimeout, pidXfer)
  12251.  * PBYTE pSrc;       // data source, or NULL for non-data cases.
  12252.  * ULONG cb;         // data size or 0 for non-data cases.
  12253.  * HCONV hConv;      // associated conversation handle
  12254.  * HSZ hszItem;      // item of transaction
  12255.  * USHORT usFmt;     // format for transaction
  12256.  * USHORT usType;    // transaction type code
  12257.  * ULONG ulTimeout;  // timeout for synchronous, TIMEOUT_ASSYNC otherwise.
  12258.  * PULONG pidXfer;   // OUTPUT: assync transfer id, NULL for no output.
  12259.  *
  12260.  * This API initiates a transaction from a client to the server connected
  12261.  * via the conversation specified by hConv.
  12262.  *
  12263.  * Currently usType may be:
  12264.  *     XTYP_REQUEST
  12265.  *     XTYP_POKE
  12266.  *     XTYP_EXEC
  12267.  *     XTYP_ADVSTART
  12268.  *     XTYP_ADVSTART | XTYPF_NODATA
  12269.  *     XTYP_ADVSTART | XTYPF_ACKREQ
  12270.  *     XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ
  12271.  *     XTYP_ADVSTOP
  12272.  *
  12273.  * ulTimeout specifies the maximum time to wait for a response in miliseconds
  12274.  * and applies to synchronous transactions only.
  12275.  * if ulTimeout is TIMEOUT_ASSYNC, then the transfer is asynchronous and
  12276.  * pidXfer may point to where to place the client transaction queue item
  12277.  * ID created by this request.
  12278.  * pidXfer may be NULL if no ID is desired.
  12279.  *
  12280.  * If usType is XTYP_REQUEST, synchronous transfers return a valid hDmgData
  12281.  * on success which holds the data received from the request.
  12282.  *
  12283.  * if usType is XTYP_EXEC and hszItem==NULL (wild) and usFmt==DDEFMT_TEXT,
  12284.  * the item name will be changed to the same as the text data.
  12285.  * This allows for EXCEL and porthole WINDOWS compatability
  12286.  * for XTYP_EXEC transactions.  It is suggested that applications always set
  12287.  * hszItem to NULL for XTYP_EXEC transactions and that servers ignore the
  12288.  * hszItem perameter in their callback for execute transactions.
  12289.  *
  12290.  * returns hDmgData or ACK DDE flags on Success, 0 on failure.
  12291.  *
  12292.  * Note: the hDmgData passed in by this call is only valid for the duration
  12293.  * of the callback.
  12294.  *
  12295.  * PUBDOC END
  12296.  *
  12297.  * History:
  12298.  *   Created     12/14/88    Sanfords
  12299.  \***************************************************************************/
  12300.  HDMGDATA EXPENTRY DdeClientXfer(pSrc, cb, hConv, hszItem, usFmt,
  12301.          usType, ulTimeout, pidXfer)
  12302.  PBYTE pSrc;
  12303.  ULONG cb;
  12304.  HCONV hConv;
  12305.  HSZ hszItem;
  12306.  USHORT usFmt;
  12307.  USHORT usType;
  12308.  ULONG ulTimeout;
  12309.  PULONG pidXfer;
  12310.  {
  12311.      PAPPINFO pai;
  12312.      XFERINFO xi;
  12313.      HDMGDATA hDmgData;
  12314.  
  12315.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  12316.          return(0);
  12317.  
  12318.      if (!WinIsWindow(DMGHAB, hConv)) {
  12319.          pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  12320.          return(0);
  12321.      }
  12322.  
  12323.      SemCheckOut();
  12324.  
  12325.      switch (usType) {
  12326.      case XTYP_REQUEST:
  12327.      case XTYP_POKE:
  12328.      case XTYP_EXEC:
  12329.      case XTYP_ADVSTART:
  12330.      case XTYP_ADVSTART | XTYPF_NODATA:
  12331.      case XTYP_ADVSTART | XTYPF_ACKREQ:
  12332.      case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  12333.      case XTYP_ADVSTOP:
  12334.          xi.pidXfer = pidXfer;
  12335.          xi.ulTimeout = ulTimeout;
  12336.          xi.usType = usType;
  12337.          xi.usFmt = usFmt;
  12338.          xi.hszItem = hszItem;
  12339.          xi.hConv = hConv;
  12340.          xi.cb = cb;
  12341.          xi.pData = pSrc;
  12342.          hDmgData = (HDMGDATA)WinSendMsg(hConv, UMCL_XFER, (MPARAM)&xi, 0L);
  12343.          if (ulTimeout == TIMEOUT_ASYNC) {
  12344.              /*
  12345.               * Increment the count of hszItem incase the app frees it on
  12346.               * return.  This will be decremented when the client Queue
  12347.               * entry is removed.
  12348.               */
  12349.              IncHszCount(hszItem);
  12350.          }
  12351.  
  12352.          /*
  12353.           * add the hDmgData to the client's list of handles he needs
  12354.           * to eventually free.
  12355.           */
  12356.          if ((usType & XCLASS_DATA) && (CheckSel(SELECTOROF(hDmgData)))) {
  12357.              AddPileItem(pai->pHDataPile, (PBYTE)&hDmgData, CmpULONG);
  12358.              if (((PMYDDES)hDmgData)->magic == MYDDESMAGIC) {
  12359.                  ((PMYDDES)hDmgData)->fs |= HDATA_READONLY;
  12360.              }
  12361.          }
  12362.  
  12363.          return(hDmgData);
  12364.      }
  12365.      pai->LastError = DMGERR_INVALIDPARAMETER;
  12366.      return(0);
  12367.  }
  12368.  
  12369.  
  12370.  
  12371.  /***************************** Public  Function ****************************\
  12372.  * PUBDOC START
  12373.  * USHORT EXPENTRY DdeGetLastError(void)
  12374.  *
  12375.  * This API returns the most recent error registered by the DDE manager for
  12376.  * the current thread.  This should be called anytime a DDE manager API
  12377.  * returns in a failed state.
  12378.  *
  12379.  * returns an error code which corresponds to a DMGERR_ constant found in
  12380.  * ddeml.h.  This error code may be passed on to DdePostError() to
  12381.  * show the user the reason for the error or to DdeGetErrorString() to convert
  12382.  * the error code into an apropriate string.
  12383.  *
  12384.  * PUBDOC END
  12385.  *
  12386.  * History:
  12387.  *   Created     12/14/88    Sanfords
  12388.  \***************************************************************************/
  12389.  USHORT EXPENTRY DdeGetLastError(void)
  12390.  {
  12391.      PAPPINFO pai;
  12392.      SHORT err = DMGERR_DLL_NOT_INITIALIZED;
  12393.  
  12394.      pai = GetCurrentAppInfo(FALSE);
  12395.  
  12396.      if (pai) {
  12397.          err = pai->LastError;
  12398.          pai->LastError = DMGERR_NO_ERROR;
  12399.      }
  12400.      return(err);
  12401.  }
  12402.  
  12403.  
  12404.  /***************************** Public  Function ****************************\
  12405.  * PUBDOC START
  12406.  * void EXPENTRY DdePostError(err)
  12407.  * ULONG err;    // error code to post.
  12408.  *
  12409.  * This API puts up a message box describing the error who's code was
  12410.  * passed in.
  12411.  *
  12412.  * PUBDOC END
  12413.  *
  12414.  * History:
  12415.  *   Created     12/20/88    sanfords
  12416.  \***************************************************************************/
  12417.  void EXPENTRY DdePostError(err)
  12418.  USHORT err;
  12419.  {
  12420.      char szError[MAX_ERRSTR + 1];
  12421.  
  12422.      if (err < DMGERR_FIRST || err > DMGERR_LAST)
  12423.          return;
  12424.      WinLoadString(DMGHAB, hmodDmg, err, MAX_ERRSTR + 1, szError);
  12425.      WinMessageBox(HWND_DESKTOP, NULL, szError, SZERRCAPTION, 0,
  12426.              MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
  12427.  }
  12428.  
  12429.  
  12430.  
  12431.  /***************************** Public  Function ****************************\
  12432.  * PUBDOC START
  12433.  * USHORT EXPENTRY DdeGetErrorString(err, cbMax, psz)
  12434.  * USHORT err;       // error code to convert
  12435.  * USHORT cbMax;     // size of string buffer provided by caller
  12436.  * PSZ psz;          // string buffer address.
  12437.  *
  12438.  * This function fills psz with the error string referenced by err of up
  12439.  * to cbMax characters.  All error strings are <= MAX_ERRSTR in length.
  12440.  * (not counting the NULL terminator.)
  12441.  *
  12442.  * returns length of copied string without NULL terminator or 0 on failure.
  12443.  *
  12444.  * PUBDOC END
  12445.  *
  12446.  * History:
  12447.  *   Created     12/20/88    sanfords
  12448.  \***************************************************************************/
  12449.  USHORT EXPENTRY DdeGetErrorString(err, cbMax, psz)
  12450.  USHORT err;
  12451.  USHORT cbMax;
  12452.  PSZ psz;
  12453.  {
  12454.      if (err < DMGERR_FIRST || err > DMGERR_LAST)
  12455.          return(0);
  12456.      return(WinLoadString(DMGHAB, hmodDmg, err, cbMax, psz));
  12457.  }
  12458.  
  12459.  
  12460.  
  12461.  /*\
  12462.  * HDATA stuff:
  12463.  *
  12464.  * Each thread has an hData list that contains all the hData's it has
  12465.  * been given by the DLL.   This list indicates what hData's an app can
  12466.  * and must eventually free.
  12467.  *
  12468.  * If an app has multiple threads registered, each threads pai's are linked
  12469.  * via the nextThread pointer.  The links are circular so the TID
  12470.  * should be used to know when all the lists are traversed.
  12471.  *
  12472.  * Each hData contains the following flags:
  12473.  *
  12474.  * HDATA_READONLY - set on any hData given to the DLL or created by the DLL.
  12475.  *         This prevents AddData from working.
  12476.  *
  12477.  * HDATA_APPOWNED - set at creation time by app so app will keep access
  12478.  *         until it frees it or unregistration happens.
  12479.  *         This prevents the DLL from freeing the hData before an app is
  12480.  *         through with it.
  12481.  *
  12482.  * HDATA_APPFREEABLE - set at creation time if logged into thread list.
  12483.  *
  12484.  * Each hData also contains the pai of the thread that created the hData.
  12485.  *         (set by PutData)  If APPOWNED is set, this identifies the
  12486.  *         owner thread as well.
  12487.  *
  12488.  *
  12489.  * General rules for apps:
  12490.  *
  12491.  *         hDatas from DLL calls are the apps responsibility to free and are
  12492.  *                 only valid till passed back into the DLL or freed.
  12493.  *         hDatas from callback calls are only valid during the callback.
  12494.  *         hDatas created by an app but not APPOWNED are only valid till
  12495.  *                 passed into the DLL.
  12496.  *         hDatas created by an app that are APPOWNED are valid until
  12497.  *                 the creating thread frees it or till that thread unregister
  12498.  *                 itself.
  12499.  *         A process will not loose access to an hData untill all threads that
  12500.  *                 have received the hData have freed it or passed it back to
  12501.  *                 the DLL (via callback)
  12502.  *
  12503.  *
  12504.  * Register:                                                       DONE
  12505.  *         creates hDataList for app/thread.
  12506.  *         creates nextThread links if applicable.
  12507.  *
  12508.  * DdePutData:                                                  DONE
  12509.  *         Only allows HDATA_APPOWNED flag
  12510.  *         sets HDATA_APPFREEABLE flag
  12511.  *         ...Falls into....
  12512.  * PutData:                                                        DONE
  12513.  *         Allocates selector
  12514.  *         sets creator pai
  12515.  *         sets HDATA_ flags specified
  12516.  *         if (HDATA_APPFREEABLE)
  12517.  *             adds to hDataList.
  12518.  *
  12519.  * DdeAddData:                                                  DONE
  12520.  *         fails if HDATA_READONLY or a non-dll type selector
  12521.  *
  12522.  * Callback:                                                       DONE
  12523.  *         Entry:
  12524.  *             for hData to callback:
  12525.  *                 Sets HDATA_READONLY if hData valid DLL type selector.
  12526.  *                 (does NOT add hData to thread list so he can't free it duri
  12527.  *                  the callback)
  12528.  *
  12529.  *         Exit:
  12530.  *             for hData to callback:
  12531.  *                 nothing.
  12532.  *             for hData from callback:
  12533.  *                 verifies creator == current
  12534.  *
  12535.  * DdeCreateInitPkt:                                            DONE
  12536.  * DdeAppNameServer:                                            NOT COMPLETE
  12537.  * DdeClientXfer:                                               DONE
  12538.  * DdeCheckQ:                                                   DONE
  12539.  *         if (valid selector)
  12540.  *             add to thread list
  12541.  *             if (valid DLL type selector)
  12542.  *                 Set READONLY flag.
  12543.  *
  12544.  * ProcessPkt:                                                     NOT IMP.
  12545.  *         for hData in:
  12546.  *              After used, calls FreeData()
  12547.  *         for hData out:
  12548.  *              before return, adds hData to thread list
  12549.  *
  12550.  * MyPostMsg:                                                      DONE
  12551.  *         gives if target process != current
  12552.  *         if target process is not a DLL process/thread, expand hszItem.
  12553.  *         calls FreeData() on current process if MDPM_FREEHDATA is set.
  12554.  *
  12555.  *
  12556.  * DdeFreeData:                                                 DONE
  12557.  *         if in thread list.
  12558.  *             remove hData from list
  12559.  *             if not in any thread lists for this process
  12560.  *                 free data
  12561.  *             return pass
  12562.  *         else
  12563.  *             return fail
  12564.  *
  12565.  * FreeData:                                                       DONE
  12566.  *         if (DLL type selector && HDATA_APPOWNED && creator == current)
  12567.  *             exit
  12568.  *         remove hData from thread list if found
  12569.  *         if not in any thread lists for this process
  12570.  *             free data
  12571.  *
  12572.  * UnRegister:                                                     DONE
  12573.  *         for each item in the hDataList:
  12574.  *             clear HDATA_APPOWNED flag if dll type selector and owned by thi
  12575.  *                 thread.
  12576.  *             FreeData()
  12577.  *         destroy list
  12578.  *         unlink from other thread lists
  12579.  *
  12580.  \*/
  12581.  
  12582.  
  12583.  /***************************** Public  Function ****************************\
  12584.  * PUBDOC START
  12585.  * HDMGDATA EXPENTRY DdePutData(pSrc, cb, cbOff, hszItem, usFmt, afCmd)
  12586.  * PBYTE pSrc;   // address of data to place into data handle or NULL
  12587.  * ULONG cb;     // amount of data to copy if pSrc is not NULL.
  12588.  * ULONG cbOff;  // offset into data handle region to place pSrc data
  12589.  * HSZ hszItem;  // item associated with this data
  12590.  * USHORT usFmt; // format associated with this data
  12591.  * USHORT afCmd; // HDATA_ flags.
  12592.  *
  12593.  * This api allows an application to create a hDmgData apropriate
  12594.  * for return from its call-back function.
  12595.  * The passed in data is stored into the hDmgData which is
  12596.  * returned on success.  Any portions of the data handle not filled are
  12597.  * undefined.  afCmd contains any of the HDATA_ constants described below:
  12598.  *
  12599.  * HDATA_APPOWNED
  12600.  *   This declares the created data handle to be the responsability of
  12601.  *   the application to free it.  Application owned data handles may
  12602.  *   be given to the DLL multiple times.  This allows a server app to be
  12603.  *   able to support many clients without having to recopy the data for
  12604.  *   each request.  If this flag is not specified, the data handle becomes
  12605.  *   invalid once passed to the DLL via any API or the callback function.
  12606.  *
  12607.  * NOTES:
  12608.  *   If an application expects this data handle to hold >64K of data via
  12609.  *   DdeAddData(), it should specify a cb + cbOff to be as large as
  12610.  *   the object is expected to get via DdeAddData() calls to avoid
  12611.  *   unnecessary data copying or reallocation by the DLL.
  12612.  *
  12613.  *   if psrc==NULL or cb == 0, no actual data copying takes place.
  12614.  *
  12615.  *   Data handles given to an application via the DdeClientXfer() or
  12616.  *   DdeCheckQueue() functions are the responsability of the client
  12617.  *   application to free and MUST NOT be returned from the callback
  12618.  *   function as server data!  The DLL will only accept data handles
  12619.  *   returned from the callback function that were created by the
  12620.  *   called application.
  12621.  *
  12622.  * PUBDOC END
  12623.  *
  12624.  * History:
  12625.  *   Created     12/14/88    Sanfords
  12626.  \***************************************************************************/
  12627.  HDMGDATA EXPENTRY DdePutData(pSrc, cb, cbOff, hszItem, usFmt, afCmd)
  12628.  PBYTE pSrc;
  12629.  ULONG cb;
  12630.  ULONG cbOff;
  12631.  HSZ hszItem;
  12632.  USHORT usFmt;
  12633.  USHORT afCmd;
  12634.  {
  12635.      PAPPINFO pai;
  12636.  
  12637.      if (!(pai = GetCurrentAppInfo(FALSE)))
  12638.          return(0L);;
  12639.  
  12640.      if (afCmd & ~(HDATA_APPOWNED)) {
  12641.          pai->LastError = DMGERR_INVALIDPARAMETER;
  12642.          return(0L);
  12643.      }
  12644.  
  12645.      return(PutData(pSrc, cb, cbOff, hszItem, usFmt, afCmd | HDATA_APPFREEABLE
  12646.  }
  12647.  
  12648.  
  12649.  /***************************** Public  Function ****************************\
  12650.  * PUBDOC START
  12651.  * HDMGDATA EXPENTRY DdeAddData(hDmgData, pSrc, cb, cbOff)
  12652.  * HDMGDATA hDmgData;    // data handle to add data to
  12653.  * PBYTE pSrc;           // pointer to data to add (if NULL, no data copying)
  12654.  * ULONG cb;             // size of data to add
  12655.  * ULONG cbOff;          // offset within hData to place data
  12656.  *
  12657.  * This routine allows an application to add data to a hDmgData it had
  12658.  * previously created using DdePutData().  The handle will be
  12659.  * grown as necessary to support the data addition.  Data may be added
  12660.  * to a data handle multiple times and in any order of data locations.
  12661.  *
  12662.  * Once a data handle is given to the DLL via return from the callback
  12663.  * function or via a DLL API, it becomes readonly.  Further attempts to
  12664.  * add data to the hData by any process will fail.
  12665.  *
  12666.  * This call will return 0 if it failed to allocate enough memory or if
  12667.  * the data handle is readonly.  On success, the returned hDmgData should
  12668.  * replace the given hDmgData.  On failure, the hDmgData given is left
  12669.  * in the state it was initially.
  12670.  *
  12671.  * NOTE: For huge segments, or segments expected to grow to greater than
  12672.  *    64K, it is best if DdePutData() be called with a cbOff + cb as
  12673.  *    large as maximally expected so as not to force reallocation from a
  12674.  *    normal to a huge segment in 16bit applications.  This also avoids
  12675.  *    the need of replaceing the hDmgData with the output each time
  12676.  *    incase a new selector was needed to be allocated and copied to.
  12677.  *
  12678.  * PUBDOC END
  12679.  *
  12680.  * History:
  12681.  *   Created     9/17/89    Sanfords
  12682.  \***************************************************************************/
  12683.  HDMGDATA EXPENTRY DdeAddData(hDmgData, pSrc, cb, cbOff)
  12684.  HDMGDATA hDmgData;
  12685.  PBYTE pSrc;
  12686.  ULONG cb;
  12687.  ULONG cbOff;
  12688.  {
  12689.  #define pmyddes ((PMYDDES)hDmgData)
  12690.  #define selIn (SELECTOROF(hDmgData))
  12691.  
  12692.      PAPPINFO pai;
  12693.      SEL sel;
  12694.      ULONG cbOffAbs;
  12695.  
  12696.      if (!(pai = GetCurrentAppInfo(FALSE)))
  12697.          return(0L);;
  12698.  
  12699.      if (!CheckSel(selIn) ||
  12700.              pmyddes->offszItemName != sizeof(MYDDES) ||
  12701.              pmyddes->magic != MYDDESMAGIC ||
  12702.              pmyddes->fs & HDATA_READONLY) {
  12703.          pai->LastError = DMGERR_INVALID_HDMGDATA;
  12704.          return(0L);
  12705.      }
  12706.  
  12707.      cbOffAbs = pmyddes->offabData + cbOff;
  12708.      if (pmyddes->cbData + pmyddes->offabData < cb + cbOffAbs) {
  12709.          /*
  12710.           * need to grow...
  12711.           */
  12712.          if (cbOffAbs + cb > 0xFFFFL) {
  12713.              /*
  12714.               * going to be huge...
  12715.               */
  12716.              if ((pmyddes->offabData + pmyddes->cbData < 0xFFFFL) ||
  12717.                      DosReallocHuge(HIUSHORT(cb + cbOffAbs),
  12718.                      LOUSHORT(cb + cbOffAbs), selIn)) {
  12719.                  /*
  12720.                   * Either we can't grow a huge seg or we need to make one.
  12721.                   */
  12722.                  if (DosAllocHuge(HIUSHORT(cb + cbOffAbs),
  12723.                          LOUSHORT(cb + cbOffAbs), &sel, 0, SEG_GIVEABLE)) {
  12724.                      pai->LastError = DMGERR_MEMORY_ERROR;
  12725.                      return(0);
  12726.                  }
  12727.                  CopyHugeBlock(hDmgData, MAKEP(sel, 0), pmyddes->cbData +
  12728.                          sizeof(MYDDES) + 1);
  12729.                  FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&hDmgData,
  12730.                          FPI_DELETE);
  12731.                  DosFreeSeg(selIn);
  12732.                  hDmgData = MAKEP(sel, 0);
  12733.                  AddPileItem(pai->pHDataPile, (PBYTE)&hDmgData, NULL);
  12734.              }
  12735.          } else {
  12736.              /*
  12737.               * not going to be huge
  12738.               */
  12739.              if (DosReallocSeg((USHORT)(cb + cbOffAbs), selIn)) {
  12740.                  pai->LastError = DMGERR_MEMORY_ERROR;
  12741.                  return(0L);
  12742.              }
  12743.          }
  12744.          pmyddes->cbData = cbOff + cb;
  12745.      }
  12746.      if (pSrc)
  12747.          CopyHugeBlock(pSrc, HugeOffset((PBYTE)hDmgData, cbOffAbs), cb);
  12748.      return(hDmgData);
  12749.  #undef selIn
  12750.  #undef pmyddes
  12751.  }
  12752.  
  12753.  
  12754.  /***************************** Public  Function ****************************\
  12755.  * PUBDOC START
  12756.  * ULONG EXPENTRY DdeGetData(hDmgData, pDst, cbMax, cbOff)
  12757.  * HDMGDATA hDmgData;    // data handle to extract data from
  12758.  * PBYTE pDst;           // destination for extracted data
  12759.  * ULONG cbMax;          // destination buffer size
  12760.  * ULONG cbOff;          // offset into data to start extraction
  12761.  *
  12762.  * This copies up to cbMax bytes of data contained in the hDmgData data handle
  12763.  * at offset cbOff into application memory pointed to by pDst.
  12764.  * If pDst == NULL, no copying is performed.
  12765.  *
  12766.  * returns the size of the data contained in the data handle remaining after
  12767.  * cbOff or 0 if hDmgData is invalid or cbOff is too large.
  12768.  *
  12769.  * This API supports HUGE segments in 16 bit applications.
  12770.  *
  12771.  * PUBDOC END
  12772.  *
  12773.  * History:
  12774.  *   Created     12/14/88    Sanfords
  12775.  \***************************************************************************/
  12776.  ULONG EXPENTRY DdeGetData(hDmgData, pDst, cbMax, cbOff)
  12777.  HDMGDATA hDmgData;
  12778.  PBYTE pDst;
  12779.  ULONG cbMax;
  12780.  ULONG cbOff;
  12781.  {
  12782.      PAPPINFO pai;
  12783.  
  12784.      if ((pai = GetCurrentAppInfo(FALSE)) == NULL)
  12785.          return(0L);
  12786.  
  12787.      if (!CheckSel(SELECTOROF(hDmgData))) {
  12788.          pai->LastError = DMGERR_INVALID_HDMGDATA;
  12789.          return(0L);
  12790.      }
  12791.      if (cbOff >= ((PMYDDES)hDmgData)->cbData) {
  12792.          pai->LastError = DMGERR_INVALIDPARAMETER;
  12793.          return(0L);
  12794.      }
  12795.      cbMax = min(cbMax, ((PMYDDES)hDmgData)->cbData - cbOff);
  12796.      if (pDst == NULL)
  12797.          return(((PMYDDES)hDmgData)->cbData - cbOff);
  12798.      CopyHugeBlock(HugeOffset(DDES_PABDATA(hDmgData), cbOff), pDst, cbMax);
  12799.      return(cbMax);
  12800.  }
  12801.  
  12802.  
  12803.  
  12804.  /***************************** Public  Function ****************************\
  12805.  * PUBDOC START
  12806.  * PBYTE EXPENTRY DdeAccessData(hDmgData)
  12807.  * HDMGDATA hDmgData;    // data handle to access
  12808.  *
  12809.  * This API returns a pointer to the data referenced by the data handle.
  12810.  * The pointer returned becomes invalid once the data handle is freed
  12811.  * or given to the DLL via callback return or API call.
  12812.  *
  12813.  * NOTE: applications MUST take care not to access beyond the limits of
  12814.  * the data handle.  Only hDmgData's created by the application via
  12815.  * a DdePutData() call may write to this memory prior to passing on
  12816.  * to any DLL API or returning from the callback function.  Any hDmgData
  12817.  * received from the DLL should be considered shared-readonly data and
  12818.  * should be treated as such.  This applies whether the application owns
  12819.  * the data handle or not.
  12820.  *
  12821.  * 0L is returned on error.
  12822.  *
  12823.  * PUBDOC END
  12824.  *
  12825.  * History:
  12826.  *   Created     8/24/88    Sanfords
  12827.  \***************************************************************************/
  12828.  PBYTE EXPENTRY DdeAccessData(hDmgData)
  12829.  HDMGDATA hDmgData;
  12830.  {
  12831.      PAPPINFO pai;
  12832.  
  12833.      if ((pai = GetCurrentAppInfo(FALSE)) == NULL)
  12834.          return(0L);
  12835.      if (CheckSel(SELECTOROF(hDmgData))) {
  12836.          return(DDES_PABDATA(hDmgData));
  12837.      }
  12838.      pai->LastError = DMGERR_ACCESS_DENIED;
  12839.      return(0L);
  12840.  }
  12841.  
  12842.  
  12843.  
  12844.  
  12845.  /***************************** Public  Function ****************************\
  12846.  * PUBDOC START
  12847.  * BOOL EXPENTRY DdeFreeData(hDmgData)
  12848.  * HDMGDATA hDmgData;        // data handle to destroy
  12849.  *
  12850.  * This routine should be called by an application wishing to release
  12851.  * custody of an hDmgData it owns.
  12852.  * An application owns any hDmgData
  12853.  * it created with the HDATA_APPOWNED flag or an hDmgData given to
  12854.  * it via DdeClientXfer(), DdeCheckQueue(), DdeAppNameServer(),
  12855.  * DdeCreateInitPkt() or DdeProcessPkt().
  12856.  *
  12857.  * Returns fSuccess.  This function will fail if the hDmgData is not
  12858.  * owned by the calling app.
  12859.  *
  12860.  * PUBDOC END
  12861.  * History:
  12862.  *   Created     12/14/88    Sanfords
  12863.  *   6/12/90 sanfords    Fixed to work with non-DLL generated selectors
  12864.  \***************************************************************************/
  12865.  BOOL EXPENTRY DdeFreeData(hDmgData)
  12866.  HDMGDATA hDmgData;
  12867.  {
  12868.      PAPPINFO pai;
  12869.      USHORT cbSel;
  12870.      TID tid;
  12871.  
  12872.      if ((pai = GetCurrentAppInfo(FALSE)) == NULL)
  12873.          return(FALSE);
  12874.  
  12875.      cbSel = CheckSel(SELECTOROF(hDmgData));
  12876.      if (!cbSel) {
  12877.          pai->LastError = DMGERR_INVALID_HDMGDATA;
  12878.          return(FALSE);
  12879.      }
  12880.      SemEnter();
  12881.      /*
  12882.       * Apps can only free handles the DLL does not own or handles from extern
  12883.       * non-DLL DDE apps.
  12884.       */
  12885.      if (!FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&hDmgData, FPI_DELETE
  12886.          pai->LastError = DMGERR_INVALID_HDMGDATA;
  12887.          SemLeave();
  12888.          return(FALSE);
  12889.      }
  12890.  
  12891.      tid = pai->tid;
  12892.      do {
  12893.          if (FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&hDmgData, FPI_COU
  12894.              SemLeave();
  12895.              return(TRUE);
  12896.          }
  12897.          pai = pai->nextThread;
  12898.      } while (pai && pai->tid != tid);
  12899.      DosFreeSeg(SELECTOROF(hDmgData));
  12900.  
  12901.      SemLeave();
  12902.      return(TRUE);
  12903.  }
  12904.  
  12905.  
  12906.  
  12907.  /***************************** Public  Function ****************************\
  12908.  * PUBDOC START
  12909.  * BOOL EXPENTRY DdeCopyBlock(pSrc, pDst, cb)
  12910.  * PBYTE pSrc;   // source of copy
  12911.  * PBYTE pDst;   // destination of copy
  12912.  * ULONG cb;     // size in bytes of copy
  12913.  *
  12914.  * This copy utility can handle HUGE segments and can be used by any
  12915.  * application as a copy utility.  This does not support overlapping huge
  12916.  * copies.
  12917.  *
  12918.  * Returns fSuccess.
  12919.  *
  12920.  * PUBDOC END
  12921.  * History:      1/1/89  created         sanfords
  12922.  \***************************************************************************/
  12923.  BOOL EXPENTRY DdeCopyBlock(pSrc, pDst, cb)
  12924.  PBYTE pSrc;
  12925.  PBYTE pDst;
  12926.  ULONG cb;
  12927.  {
  12928.      return(CopyHugeBlock(pSrc, pDst, cb));
  12929.  }
  12930.  
  12931.  
  12932.  
  12933.  
  12934.  /***************************************************************************\
  12935.  * PUBDOC START
  12936.  * HSZ management notes:
  12937.  *
  12938.  *   HSZs are used in this DLL to simplify string handling for applications
  12939.  *   and for inter-process communication.  Since many applications use a
  12940.  *   fixed set of Application/Topic/Item names, it is convenient to convert
  12941.  *   them to HSZs and allow quick comparisons for lookups.  This also frees
  12942.  *   the DLL up from having to constantly provide string buffers for copying
  12943.  *   strings between itself and its clients.
  12944.  *
  12945.  *   HSZs are the same as atoms except they have no restrictions on length or
  12946.  *   number and are 32 bit values.  They are case preserving and can be
  12947.  *   compared directly for case sensitive comparisons or via DdeCmpHsz()
  12948.  *   for case insensitive comparisons.
  12949.  *
  12950.  *   When an application creates an HSZ via DdeGetHsz() or increments its
  12951.  *   count via DdeIncHszCount() it is essentially claiming the HSZ for
  12952.  *   its own use.  On the other hand, when an application is given an
  12953.  *   HSZ from the DLL via a callback, it is using another application's HSZ
  12954.  *   and should not free that HSZ via DdeFreeHsz().
  12955.  *
  12956.  *   The DLL insures that during the callback any HSZs given will remain
  12957.  *   valid for the duration of the callback.
  12958.  *
  12959.  *   If an application wishes to keep that HSZ to use for itself as a
  12960.  *   standard for future comparisons, it should increment its count so that,
  12961.  *   should the owning application free it, the HSZ will not become invalid.
  12962.  *   This also prevents an HSZ from changing its value.  (ie, app A frees it
  12963.  *   and then app B creates a new one that happens to use the same HSZ code,
  12964.  *   then app C, which had the HSZ stored all along (but forgot to increment
  12965.  *   its count) now is holding a handle to a different string.)
  12966.  *
  12967.  *   Applications may free HSZs they have created or incremented at any time
  12968.  *   by calling DdeFreeHsz().
  12969.  *
  12970.  *   The DLL internally increments HSZ counts while in use so that they will
  12971.  *   not be destroyed until both the DLL and all applications concerned are
  12972.  *   through with them.
  12973.  *
  12974.  *   IT IS THE APPLICATIONS RESPONSIBILITY TO PROPERLY CREATE AND FREE HSZs!!
  12975.  *
  12976.  * PUBDOC END
  12977.  \***************************************************************************/
  12978.  
  12979.  
  12980.  /***************************** Public  Function ****************************\
  12981.  * PUBDOC START
  12982.  * HSZ EXPENTRY DdeGetHsz(psz, country, codepage)
  12983.  * PSZ psz;          // string to HSZize.
  12984.  * USHORT country;   // country ID to use in comparisons.
  12985.  * USHORT codepage;  // codepage to use in comparisons.
  12986.  *
  12987.  * This routine returns a string handle to the psz passed in.
  12988.  * 0 is returned on failure or for NULL strings.
  12989.  *
  12990.  * If country is 0, the default system country code is used.
  12991.  * If codepage is 0, the default system codepage code is used.
  12992.  *
  12993.  * String handles are similar to atoms but without the 255
  12994.  * character limit on strings.  String handles are case preserving.
  12995.  * see DdeCmpHsz().
  12996.  *
  12997.  * String handles are consistant across all processes using the DLL.
  12998.  *
  12999.  * PUBDOC END
  13000.  *
  13001.  * History:      1/1/89 created         sanfords
  13002.  \***************************************************************************/
  13003.  HSZ EXPENTRY DdeGetHsz(psz, country, codepage)
  13004.  PSZ psz;
  13005.  USHORT country, codepage;
  13006.  {
  13007.      PAPPINFO pai;
  13008.  
  13009.      if ((pai = GetCurrentAppInfo(FALSE)) == NULL)
  13010.          return(0);
  13011.  
  13012.      return(GetHsz(psz, country, codepage, TRUE));
  13013.  }
  13014.  
  13015.  
  13016.  
  13017.  /***************************** Public  Function ****************************\
  13018.  * PUBDOC START
  13019.  * BOOL EXPENTRY DdeFreeHsz(hsz)
  13020.  * HSZ hsz;      // string handle to free
  13021.  *
  13022.  * This function decrements the usage count for the HSZ given and frees
  13023.  * it if the count becomes 0.
  13024.  *
  13025.  * PUBDOC END
  13026.  *
  13027.  * History:      1/1/89 created         sanfords
  13028.  \***************************************************************************/
  13029.  BOOL EXPENTRY DdeFreeHsz(hsz)
  13030.  HSZ hsz;
  13031.  {
  13032.      PAPPINFO pai;
  13033.  
  13034.      if ((pai = GetCurrentAppInfo(FALSE)) == NULL)
  13035.          return(0);
  13036.      return(FreeHsz(hsz));
  13037.  }
  13038.  
  13039.  
  13040.  
  13041.  /***************************** Public  Function ****************************\
  13042.  * PUBDOC START
  13043.  * BOOL EXPENTRY DdeIncHszCount(hsz)
  13044.  * HSZ hsz;  // string handle to increment.
  13045.  *
  13046.  * This function increments the usage count for the HSZ given.  This is
  13047.  * useful when an application wishes to keep an HSZ given to it in its
  13048.  * callback.
  13049.  *
  13050.  * PUBDOC END
  13051.  *
  13052.  * History:      1/1/89 created         sanfords
  13053.  \***************************************************************************/
  13054.  BOOL EXPENTRY DdeIncHszCount(hsz)
  13055.  HSZ hsz;
  13056.  {
  13057.      PAPPINFO pai;
  13058.  
  13059.      if ((pai = GetCurrentAppInfo(FALSE)) == NULL)
  13060.          return(0);
  13061.  
  13062.      return(IncHszCount(hsz));
  13063.  }
  13064.  
  13065.  
  13066.  
  13067.  /***************************** Public  Function ****************************\
  13068.  * PUBDOC START
  13069.  * USHORT EXPENTRY DdeGetHszString(hsz, psz, cchMax)
  13070.  * HSZ hsz;      // string handle to extract string from
  13071.  * PSZ psz;      // buffer for case-sensitive string
  13072.  * ULONG cchMax; // buffer size.
  13073.  *
  13074.  * This API is the inverse of DdeGetHsz().  The actual length of the
  13075.  * string (without NULL terminator) referenced by hsz is returned.
  13076.  *
  13077.  * if psz is NULL, no string is returned in psz.
  13078.  * 0 is returned if hsz does not exist or is wild.
  13079.  * If hsz is wild, psz will be set to a 0 length string.
  13080.  *
  13081.  * PUBDOC END
  13082.  * History:      Created 5/10/89         sanfords
  13083.  \***************************************************************************/
  13084.  USHORT EXPENTRY DdeGetHszString(hsz, psz, cchMax)
  13085.  HSZ hsz;
  13086.  PSZ psz;
  13087.  ULONG cchMax;
  13088.  {
  13089.      if (psz) {
  13090.          if (hsz) {
  13091.              return(QueryHszName(hsz, psz, (USHORT)cchMax));
  13092.          } else {
  13093.              *psz = '\0';
  13094.              return(0);
  13095.          }
  13096.      } else if (hsz) {
  13097.          return(QueryHszLength(hsz));
  13098.      } else {
  13099.          return(0);
  13100.      }
  13101.  }
  13102.  
  13103.  
  13104.  /***************************** Public  Function ****************************\
  13105.  * PUBDOC START
  13106.  * SHORT EXPENTRY DdeCmpHsz(hsz1, hsz2)
  13107.  * HSZ hsz1, hsz2;   // string handles to compare.
  13108.  *
  13109.  * This routine returns:
  13110.  *   0  if hsz1 is of equal  rank to   hsz2
  13111.  *   -2 if hsz1 is invalid.
  13112.  *   -1 if hsz1 is of lower  rank than hsz2
  13113.  *   1  if hsz1 is of higher rank than hsz2.
  13114.  *   2  if hsz2 is invalid.
  13115.  *
  13116.  * Note that direct comparison of hszs (ie (hsz1 == hsz2)) is a case sensitive
  13117.  * comparison.  This function performs a case insensitive comparison.  Thus
  13118.  * different valued hszs may actually be equal.
  13119.  * A ranking is provided for binary searching.
  13120.  *
  13121.  * PUBDOC END
  13122.  \***************************************************************************/
  13123.  SHORT EXPENTRY DdeCmpHsz(hsz1, hsz2)
  13124.  HSZ hsz1, hsz2;
  13125.  {
  13126.      return(CmpHsz(hsz1, hsz2));
  13127.  }
  13128.  
  13129.  
  13130.  /***************************** Public  Function ****************************\
  13131.  * PUBDOC START
  13132.  * ULONG EXPENTRY DdeCheckQueue(hConv, phDmgData, idXfer, afCmd)
  13133.  * HCONV hConv;          // related convesation handle
  13134.  * PHDMGDATA phDmgData;  // OUTPUT: for resultant data handle, or NULL
  13135.  * ULONG idXfer;         // transaction ID or QID_NEWEST or QID_OLDEST
  13136.  * ULONG afCmd;          // queue operation code.
  13137.  *
  13138.  *       This routine checks a client conversation's assynchronous
  13139.  *       transaction queue for queued transaction status.  This allows a
  13140.  *       client to extract data or monitor the status of any transaction
  13141.  *       previously started asynchronously.  (TIMEOUT_ASSYNC) hConv is
  13142.  *       the client conversation who's queue is being checked.
  13143.  *
  13144.  *       If phDmgData is not NULL and the referenced item has data to
  13145.  *       return to the client, phDmgData is filled.  Returned hDmgDatas
  13146.  *       must be freed by the application.  phDmgData will be filled with
  13147.  *       0L if no return data is applicable or if the transaction is not
  13148.  *       complete.
  13149.  *
  13150.  *       If the queue is not periodicly flushed by an application
  13151.  *       issueing asynchronous transactions the queue is automaticly
  13152.  *       flushed as needed.  Oldest transactions are flushed first.
  13153.  *       DdeProcessPkt() and DdeDisconnect() and DdeEndEnumServers
  13154.  *       remove items from this queue.
  13155.  *
  13156.  *       idXfer is the transaction id returned by an asynchronous call to
  13157.  *       DdeClientXfer().
  13158.  *
  13159.  * afCmd = CQ_FLUSH - remove all items in the queue - return is fSuccess.
  13160.  * afCmd = CQ_REMOVE - the item referenced is removed from the queue.
  13161.  * afCmd = CQ_NEXT - references the idXfer AFTER (more recent than) the id
  13162.  *       given. 0 is returned if the ID given was the newest in the
  13163.  *       queue otherwise the next ID is returned.
  13164.  * afCmd = CQ_PREV - references the idXfer BEFORE (less recent than) the id
  13165.  *       given. 0 is returned if the ID given was the oldest in the
  13166.  *       queue otherwise the previous ID is returned.
  13167.  * afCmd = CQ_COUNT    - returns the number of entries in the queue.
  13168.  *
  13169.  *       By ORing in one of the following flags, the above flags can be
  13170.  *       made to reference the apropriate subset of queue entries:
  13171.  *
  13172.  * afCmd = CQ_ACTIVEONLY - incomplete active transactions only.
  13173.  * afCmd = CQ_COMPLETEDONLY - completed transactions only.
  13174.  * afCmd = CQ_FAILEDONLY - transactions which had protocol violations or
  13175.  *                         communication failures.
  13176.  * afCmd = CQ_INACTIVEONLY - The complement of CQ_ACTIVEONLY which is the
  13177.  *                           union of CQ_COMPLETEDONLY and CQ_FAILEDONLY.
  13178.  *
  13179.  * if phdmgdata = NULL, no hdmgdata is returned.
  13180.  * if idXfer == QID_NEWEST, the top-most (most recent) entry in the
  13181.  *       queue is referenced.
  13182.  * if idXfer == QID_OLDEST, the bottom-most (oldest) entry ID is
  13183.  *       referenced.
  13184.  *
  13185.  *       returns the ID of the item processed if it applies, or the count
  13186.  *       of items or fSuccess.
  13187.  *
  13188.  *
  13189.  * Standard usage examples:
  13190.  *
  13191.  *   To get the state of the oldest transaction:
  13192.  *   id = DdeCheckQueue(hConv, &hDmgData, QID_OLDEST, 0)
  13193.  *
  13194.  *   To get and flush the next completed transaction data, if there is
  13195.  *       any:
  13196.  *   id = DdeCheckQueue(hConv, &hDmgData, QID_OLDEST, CQ_REMOVE |
  13197.  *       CQ_INACTIVEONLY)
  13198.  *
  13199.  *   To flush all successfully completed transactions:
  13200.  *   DdeCheckQueue(hConv, NULL, QID_OLDEST, CQ_FLUSH | CQ_COMPLETEDONLY)
  13201.  *
  13202.  *   To see if a specific transaction is complete, and if so, to get the
  13203.  *   information and remove the transaction from the queue:
  13204.  *   if (DdeCheckQueue(hConv, &hDmgData, id, CQ_REMOVE | CQ_INACTIVEONLY))
  13205.  *       ProcessAndFreeData(hDmgData);
  13206.  *
  13207.  * PUBDOC END
  13208.  * History:      Created 6/6/89         sanfords
  13209.  \***************************************************************************/
  13210.  ULONG EXPENTRY DdeCheckQueue(hConv, phDmgData, idXfer, afCmd)
  13211.  HCONV hConv;
  13212.  PHDMGDATA phDmgData;
  13213.  ULONG idXfer;
  13214.  ULONG afCmd;
  13215.  {
  13216.      PAPPINFO pai;
  13217.      PCLIENTINFO pci;
  13218.      PCQDATA pcqd, pcqdT, pcqdEnd;
  13219.      USHORT err;
  13220.      ULONG retVal = TRUE;
  13221.      int i;
  13222.  
  13223.      if ((pai = GetCurrentAppInfo(TRUE)) == 0)
  13224.          return(0);
  13225.  
  13226.      SemCheckOut();
  13227.      SemEnter();
  13228.  
  13229.      err = DMGERR_INVALIDPARAMETER;
  13230.      if (!WinIsWindow(DMGHAB, hConv) ||
  13231.              !(BOOL)WinSendMsg(hConv, UM_QUERY, (MPARAM)Q_CLIENT, 0L) ||
  13232.              idXfer == QID_SYNC) {
  13233.          goto failExit;
  13234.      }
  13235.  
  13236.      if (!(pci = (PCLIENTINFO)WinSendMsg(hConv, UM_QUERY, (MPARAM)Q_ALL, 0L)))
  13237.          goto failExit;
  13238.  
  13239.      err = DMGERR_UNFOUND_QUEUE_ID;
  13240.      if ((pcqd = (PCQDATA)Findqi(pci->pQ, idXfer)) == NULL)
  13241.          goto failExit;
  13242.  
  13243.      /*
  13244.       * if referencing an end item, make sure it fits any subset flags.
  13245.       * If it doesn't we alter afCmd to force us to the first qualifying
  13246.       * entry in the correct direction.
  13247.       */
  13248.      if (!fInSubset(pcqd, afCmd)) {
  13249.          if (idXfer & (QID_OLDEST))
  13250.              afCmd |= CQ_NEXT;
  13251.          else if (idXfer & (QID_NEWEST))
  13252.              afCmd |= CQ_PREV;
  13253.          else if (!(afCmd & (CQ_NEXT | CQ_PREV | CQ_COUNT | CQ_FLUSH)))
  13254.              goto failExit;
  13255.      }
  13256.  
  13257.      if (afCmd & CQ_NEXT) {
  13258.          pcqdEnd = (PCQDATA)pci->pQ->pqiHead->next;
  13259.          if ((pcqd = (PCQDATA)pcqd->next) == pcqdEnd)
  13260.              goto failExit;
  13261.          while (!fInSubset(pcqd, afCmd)) {
  13262.              if ((pcqd = (PCQDATA)pcqd->next) == pcqdEnd)
  13263.                  goto failExit;
  13264.          }
  13265.      }
  13266.  
  13267.      if (afCmd & CQ_PREV) {
  13268.          pcqdEnd = (PCQDATA)pci->pQ->pqiHead;
  13269.          if ((pcqd = (PCQDATA)pcqd->prev) == pcqdEnd)
  13270.              goto failExit;
  13271.          while (!fInSubset(pcqd, afCmd)) {
  13272.              if ((pcqd = (PCQDATA)pcqd->prev) == pcqdEnd)
  13273.                  goto failExit;
  13274.          }
  13275.      }
  13276.  
  13277.      /*
  13278.       * pcqd now points to the apropriate entry
  13279.       */
  13280.  
  13281.      if (afCmd & CQ_COUNT)
  13282.          retVal = 0;
  13283.      else
  13284.          retVal = MAKEID(pcqd);
  13285.  
  13286.      /*
  13287.       * Fill phDmgData if specified.
  13288.       */
  13289.      if (phDmgData != NULL)
  13290.          if ((pcqd->xad.state == CONVST_CONNECTED) &&
  13291.                  CheckSel(SELECTOROF(pcqd->xad.pddes))) {
  13292.              *phDmgData = pcqd->xad.pddes;
  13293.              AddPileItem(pai->pHDataPile, (PBYTE)phDmgData, CmpULONG);
  13294.              if (((PMYDDES)*phDmgData)->magic == MYDDESMAGIC) {
  13295.                  ((PMYDDES)*phDmgData)->fs |= HDATA_READONLY;
  13296.              }
  13297.          } else
  13298.              *phDmgData = NULL;
  13299.  
  13300.      /*
  13301.       * remove pcqd if apropriate.
  13302.       */
  13303.      if (afCmd & (CQ_REMOVE | CQ_FLUSH)) {
  13304.          if (!FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&pcqd->xad.pddes,
  13305.                  0))
  13306.              FreeData((PMYDDES)pcqd->xad.pddes, pai);
  13307.          /*
  13308.           * Decrement the use count we incremented when the client started
  13309.           * this transaction.
  13310.           */
  13311.          FreeHsz(pcqd->XferInfo.hszItem);
  13312.          Deleteqi(pci->pQ, MAKEID(pcqd));
  13313.      }
  13314.  
  13315.      /*
  13316.       * go through entire list and flush or count if specified.
  13317.       */
  13318.      if (afCmd & (CQ_FLUSH | CQ_COUNT)) {
  13319.          pcqd = (PCQDATA)pci->pQ->pqiHead;
  13320.          for (i = pci->pQ->cItems; i; i--) {
  13321.              if (fInSubset(pcqd, afCmd)) {
  13322.                  if (afCmd & CQ_COUNT)
  13323.                      retVal++;
  13324.                  if (afCmd & CQ_FLUSH) {
  13325.                      pcqdT = (PCQDATA)pcqd->next;
  13326.                      /*
  13327.                       * Only free the data if not logged - ie the user never g
  13328.                       * copy.
  13329.                       */
  13330.                      if (!FindPileItem(pci->ci.pai->pHDataPile, CmpULONG,
  13331.                              (PBYTE)&pcqd->xad.pddes, 0))
  13332.                          FreeData((PMYDDES)pcqd->xad.pddes, pai);
  13333.                      /*
  13334.                       * Decrement the use count we incremented when the client
  13335.                       * this transaction.
  13336.                       */
  13337.                      FreeHsz(pcqd->XferInfo.hszItem);
  13338.                      Deleteqi(pci->pQ, MAKEID(pcqd));
  13339.                      pcqd = pcqdT;
  13340.                      continue;
  13341.                  }
  13342.              }
  13343.              pcqd = (PCQDATA)pcqd->next;
  13344.          }
  13345.      }
  13346.  
  13347.      SemLeave();
  13348.      SemCheckOut();
  13349.      return(retVal);
  13350.  
  13351.  failExit:
  13352.      pai->LastError = err;
  13353.      SemLeave();
  13354.      SemCheckOut();
  13355.      return(0);
  13356.  }
  13357.  
  13358.  
  13359.  
  13360.  BOOL fInSubset(pcqd, afCmd)
  13361.  PCQDATA pcqd;
  13362.  ULONG afCmd;
  13363.  {
  13364.      if (afCmd & CQ_ACTIVEONLY && (pcqd->xad.state <= CONVST_INIT1))
  13365.          return(FALSE);
  13366.  
  13367.      if (afCmd & CQ_INACTIVEONLY && (pcqd->xad.state > CONVST_INIT1))
  13368.          return(FALSE);
  13369.  
  13370.      if (afCmd & CQ_COMPLETEDONLY && (pcqd->xad.state != CONVST_CONNECTED))
  13371.          return(FALSE);
  13372.  
  13373.      if (afCmd & CQ_FAILEDONLY && (pcqd->xad.state > CONVST_TERMINATED))
  13374.          return(FALSE);
  13375.      return(TRUE);
  13376.  }
  13377.  
  13378.  
  13379.  
  13380.  /***************************** Public  Function ****************************\
  13381.  * PUBDOC START
  13382.  * BOOL EXPENTRY DdeEnableCallback(hConv, fEnable)
  13383.  * HCONV hConv;      // server conversation handle to enable/disable or NULL
  13384.  * BOOL fEnable;     // TRUE enables, FALSE disables callbacks.
  13385.  *
  13386.  * This routine is used by an application that does not want to be interrupted
  13387.  * by DLL calls to its Callback function.  When callbacks are disabled,
  13388.  * all non critical attempts to call the Callback function instead result in
  13389.  * the call being placed on a server transaction queue until callbacks are
  13390.  * reenabled.  An application should reenable callbacks in a timely manner
  13391.  * to avoid causing synchronous clients to time out.
  13392.  *
  13393.  * note that DdeProcessPkt() has the side effect of unblocking and removing
  13394.  * items from the server transaction queue when processing return packets.
  13395.  * DdeDisconnect() and DdeEndEnumServers() have the side effect of removing
  13396.  * any transactions for the disconnected conversation.
  13397.  *
  13398.  * If hConv is non-NULL, only the hConv conversation is affected.
  13399.  * If hConv is NULL, all conversations are affected.
  13400.  *
  13401.  * Callbacks can also be disabled on return from the callback function by
  13402.  * returning the constant CBR_BLOCK.  This has the same effect as
  13403.  * calling DdeEnableCallback(hConv, FALSE) except that the callback
  13404.  * returned from is placed back on the callback queue for later re-submission
  13405.  * to the callback function when the conversations callbacks are reenabled.
  13406.  * This allows a server that needs a long time to process a request to delay
  13407.  * returning the result without blocking within the callback function.
  13408.  *
  13409.  * No callbacks are made within this function.
  13410.  *
  13411.  * Note:  Callback transactions that have XTYPF_NOBLOCK set in their usType
  13412.  *       parameter cannot be blocked by CBR_BLOCK.
  13413.  *       These callbacks are issued to the server regardless of the state of
  13414.  *       callback enableing.
  13415.  *
  13416.  * fSuccess is returned.
  13417.  *
  13418.  * PUBDOC END
  13419.  * History:      Created 6/6/89         sanfords
  13420.  \***************************************************************************/
  13421.  BOOL EXPENTRY DdeEnableCallback(hConv, fEnable)
  13422.  HCONV hConv;
  13423.  BOOL fEnable;
  13424.  {
  13425.      PAPPINFO pai;
  13426.  
  13427.      if ((pai = GetCurrentAppInfo(TRUE)) == 0)
  13428.          return(FALSE);
  13429.  
  13430.      SemCheckOut();
  13431.      SemEnter();
  13432.      if (hConv == NULL) {
  13433.          pai->fEnableCB = fEnable = fEnable ? TRUE : FALSE;
  13434.          FlushLst(pai->plstCBExceptions);
  13435.      } else if (pai->fEnableCB != fEnable) {
  13436.          if (pai->plstCBExceptions == NULL)
  13437.              pai->plstCBExceptions = CreateLst(pai->hheapApp, sizeof(HWNDLI));
  13438.          AddHwndList((HWND)hConv, pai->plstCBExceptions);
  13439.      }
  13440.      SemLeave();
  13441.      if (fEnable)
  13442.          WinPostMsg(pai->hwndDmg, UM_CHECKCBQ, (MPARAM)pai, 0L);
  13443.      return(TRUE);
  13444.  }
  13445.  
  13446.  
  13447.  
  13448.  /***************************** Public  Function ****************************\
  13449.  * PUBDOC START
  13450.  * HDMGDATA EXPENTRY DdeAppNameServer(hszApp, afCmd);
  13451.  * HSZ hszApp;       // referenced app name
  13452.  * USHORT afCmd;     // action code.
  13453.  *
  13454.  * Updates or queries the DDE DLL application name server.  The DDE name
  13455.  * server acts as a filter for initiate messages on behalf of registered
  13456.  * applications and serves as a way for an application to determine what
  13457.  * other applications are available without the need for wild initiates.
  13458.  * Any change in the name server results in XTYP_REGISTER or XTYP_UNREGISTER
  13459.  * callbacks to all other applications.  Agents will not be allowed to
  13460.  * know about any other agent registrations.
  13461.  *
  13462.  * afCmd:
  13463.  *
  13464.  *   ANS_REGISTER
  13465.  *       Adds hszApp to the name server.  hszApp cannot be NULL.
  13466.  *       All other applications will receive a registration notification
  13467.  *       if their callback filters allow it.
  13468.  *       fSuccess is returned.
  13469.  *
  13470.  *   ANS_UNREGISTER
  13471.  *       Remove hszApp from the name server.  If hszApp==NULL the name server
  13472.  *       is cleared for the calling application.
  13473.  *       All other applications will receive a deregistration notification
  13474.  *       if their callback filters allow it.
  13475.  *       fSuccess is returned.
  13476.  *
  13477.  *   ANS_QUERYALLBUTME
  13478.  *       Returns a zero terminated array of hszApps/hApp pairs registered with
  13479.  *       the name server by all other applications.
  13480.  *       (Agent applications do not see other agent registered names.)
  13481.  *       If hszApp is set, only names matching* hszApp are placed into the lis
  13482.  *       0 is returned if no applicable names were found.
  13483.  *
  13484.  *   ANS_QUERYMINE
  13485.  *       Returns a zero terminated array of hszApps registered with the name
  13486.  *       server by the calling application.  If hszApp is set, only names
  13487.  *       matching hszApp are placed into the list.  0 is returned if no
  13488.  *       applicable names were found.
  13489.  *
  13490.  *   The following flags may be ORed in with one of the above flags:
  13491.  *
  13492.  *   ANS_FILTERON
  13493.  *       Turns on dde initiate callback filtering.  Only wild app names or
  13494.  *       those matching a registered name are given to the application for
  13495.  *       initiate requests or registration notifications.
  13496.  *
  13497.  *   ANS_FILTEROFF
  13498.  *       Turns off dde initiate callback filtering.  All initiate requests
  13499.  *       and registration notifications are passed onto the application.
  13500.  *
  13501.  * A 0 is returned on error.
  13502.  *
  13503.  * PUBDOC END
  13504.  *
  13505.  * History:
  13506.  \***************************************************************************/
  13507.  HDMGDATA EXPENTRY DdeAppNameServer(hszApp, afCmd)
  13508.  HSZ hszApp;
  13509.  USHORT afCmd;
  13510.  {
  13511.      PAPPINFO pai, paiT;
  13512.      BOOL fAgent;
  13513.      HDMGDATA hData;
  13514.      HSZ hsz;
  13515.  
  13516.      if ((pai = GetCurrentAppInfo(TRUE)) == 0)
  13517.          return(FALSE);
  13518.  
  13519.      if (afCmd & ANS_FILTERON)
  13520.          pai->afCmd |= DMGCMD_FILTERINITS;
  13521.  
  13522.      if (afCmd & ANS_FILTEROFF)
  13523.          pai->afCmd &= ~DMGCMD_FILTERINITS;
  13524.  
  13525.  
  13526.      if (afCmd & (ANS_REGISTER | ANS_UNREGISTER)) {
  13527.  
  13528.          if (pai->afCmd & DMGCMD_CLIENTONLY) {
  13529.              pai->LastError = DMGERR_DLL_USAGE;
  13530.              return(FALSE);
  13531.          }
  13532.  
  13533.          fAgent = pai->afCmd & DMGCMD_AGENT ? TRUE : FALSE;
  13534.  
  13535.          if (hszApp == NULL) {
  13536.              if (afCmd & ANS_REGISTER) {
  13537.                  /*
  13538.                   * registering NULL is not allowed!
  13539.                   */
  13540.                  pai->LastError = DMGERR_INVALIDPARAMETER;
  13541.                  return(FALSE);
  13542.              }
  13543.              /*
  13544.               * unregistering NULL is just like unregistering each
  13545.               * registered name.
  13546.               */
  13547.              while (PopPileSubitem(pai->pAppNamePile, (PBYTE)&hsz)) {
  13548.                  for (paiT = pAppInfoList; paiT; paiT = paiT->next) {
  13549.                      if (pai == paiT || (fAgent && (paiT->afCmd & DMGCMD_AGENT
  13550.                          continue;
  13551.                      WinPostMsg(paiT->hwndFrame, UM_UNREGISTER, (MPARAM)hsz,
  13552.                              (MPARAM)pai->hwndFrame);
  13553.                  }
  13554.              }
  13555.              return(TRUE);
  13556.          }
  13557.  
  13558.          if (afCmd & ANS_REGISTER) {
  13559.              if (pai->pAppNamePile == NULL)
  13560.                  pai->pAppNamePile = CreatePile(hheapDmg, sizeof(HSZ), 8);
  13561.              AddPileItem(pai->pAppNamePile, (PBYTE)&hszApp, NULL);
  13562.          } else
  13563.              FindPileItem(pai->pAppNamePile, CmpULONG, (PBYTE)&hszApp,
  13564.                      FPI_DELETE);
  13565.  
  13566.          for (paiT = pAppInfoList; paiT; paiT = paiT->next) {
  13567.              if (pai == paiT ||
  13568.                      (fAgent && (paiT->afCmd & DMGCMD_AGENT))) {
  13569.                  continue;
  13570.              }
  13571.              WinPostMsg(paiT->hwndFrame,
  13572.                      afCmd & ANS_REGISTER ? UM_REGISTER : UM_UNREGISTER,
  13573.                      (MPARAM)hszApp, (MPARAM)pai->hwndFrame);
  13574.          }
  13575.          return(TRUE);
  13576.      }
  13577.  
  13578.      if (afCmd & ANS_QUERYMINE) {
  13579.          hData = PutData(NULL, 10L * sizeof(HSZ),
  13580.                  0L, 0L, 0, HDATA_APPOWNED | HDATA_APPFREEABLE, pai);
  13581.          if (QueryAppNames(pai, hData, hszApp, 0L)) {
  13582.              return(hData);
  13583.          } else {
  13584.              DdeFreeData(hData);
  13585.              return(0L);
  13586.          }
  13587.      }
  13588.  
  13589.      if (afCmd & ANS_QUERYALLBUTME) {
  13590.          ULONG offAdd, offAddNew;
  13591.  
  13592.          hData = PutData(NULL, 10L * sizeof(HSZ),
  13593.                  0L, 0L, 0, HDATA_APPOWNED | HDATA_APPFREEABLE, pai);
  13594.          *((PHSZ)DDES_PABDATA((PDDESTRUCT)hData)) = 0L;
  13595.          SemEnter();
  13596.          paiT = pAppInfoList;
  13597.          offAdd = 0L;
  13598.          while (paiT) {
  13599.              if (paiT != pai &&
  13600.                      !(fAgent && (paiT->afCmd & DMGCMD_AGENT))) {
  13601.                  offAddNew = QueryAppNames(paiT, hData, hszApp, offAdd);
  13602.                  if (offAddNew == 0 && offAddNew < offAdd) {
  13603.                      /*
  13604.                       * memory error most likely.
  13605.                       */
  13606.                      SemLeave();
  13607.                      DdeFreeData(hData);
  13608.                      return(0L);
  13609.                  }
  13610.                  offAdd = offAddNew;
  13611.              }
  13612.              paiT = paiT->next;
  13613.          }
  13614.          SemLeave();
  13615.          return(hData);
  13616.      }
  13617.  
  13618.      return(0L);
  13619.  }
  13620.  
  13621.  
  13622.  
  13623.  /***************************** Public  Function ****************************\
  13624.  * PUBDOC START
  13625.  * HDMGDATA EXPENTRY DdeCreateInitPkt(
  13626.  * HSZ hszApp,         // initiate app string
  13627.  * HSZ hszTopic,       // initiate topic string
  13628.  * HDMGDATA hDmgData)  // packet data containing language information.
  13629.  *
  13630.  * This routine is called by agent applications from within their callback
  13631.  * functions which need to store transaction initiate data into a
  13632.  * network-portable packet.  On return, HDMGDATA contains the packeted
  13633.  * data.  The calling application must free this data handle when
  13634.  * through.  Agents are given access to the app string so that they
  13635.  * can modify it if needed for their net protocol.
  13636.  *
  13637.  * PUBDOC END
  13638.  \***************************************************************************/
  13639.  HDMGDATA EXPENTRY DdeCreateInitPkt(hszApp, hszTopic, hDmgData)
  13640.  HSZ hszApp;
  13641.  HSZ hszTopic;
  13642.  HDMGDATA hDmgData;
  13643.  {
  13644.      PAPPINFO pai;
  13645.  
  13646.      hszApp;
  13647.      hszTopic;
  13648.      hDmgData;
  13649.  
  13650.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  13651.          return(0);
  13652.      /*
  13653.       * Add hDataRet to thread list
  13654.       */
  13655.      pai->LastError = DMGERR_NOT_IMPLEMENTED;
  13656.  }
  13657.  
  13658.  
  13659.  /***************************** Public  Function ****************************\
  13660.  * PUBDOC START
  13661.  * BOOL EXPENTRY DdeProcessPkt(
  13662.  * HDMGDATA hPkt,        // packet from net to process
  13663.  * ULONG hAgentFrom);    // foreign agent handle associated with this packet.
  13664.  *
  13665.  * This routine is called by agent applications which have received a packet
  13666.  * from another agent.  This call performs what actions are requested by the
  13667.  * hPkt.  If the particular transaction can be done synchronously, a return
  13668.  * packet is returned.  If not, an XTYP_RTNPKT callback will eventually be
  13669.  * sent to the agent and 0 is returned.  0 is also returned on error.
  13670.  *
  13671.  * hAgentFrom identifies the agent the packet came from.
  13672.  *
  13673.  * This call should NOT be made from within a callback.
  13674.  *
  13675.  * PUBDOC END
  13676.  \***************************************************************************/
  13677.  HDMGDATA EXPENTRY DdeProcessPkt(hPkt, hAgentFrom)
  13678.  HDMGDATA hPkt;
  13679.  ULONG hAgentFrom;
  13680.  {
  13681.      PAPPINFO pai;
  13682.  
  13683.      hPkt;
  13684.      hAgentFrom;
  13685.  
  13686.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  13687.          return(0);
  13688.      pai->LastError = DMGERR_NOT_IMPLEMENTED;
  13689.  }
  13690.  
  13691.  
  13692.  
  13693.  /***************************** Public  Function ****************************\
  13694.  * PUBDOC START
  13695.  * ULONG EXPENTRY DdeQueryVersion()
  13696.  *
  13697.  * Returns the DLL version number: 0xjjmmuuppL
  13698.  * jj = major release;
  13699.  * mm = minor release;
  13700.  * uu = update number;
  13701.  * pp = platform ID; 1=OS/2, 2=DOS, 3=WINDOWS, 4=UNIX, 5=MAC, 6=SUN
  13702.  *
  13703.  *
  13704.  * PUBDOC END
  13705.  \***************************************************************************/
  13706.  ULONG EXPENTRY DdeQueryVersion()
  13707.  {
  13708.      return(MAKEULONG(MAKESHORT(1, rup),MAKESHORT(rmm, rmj)));
  13709.  }
  13710.  
  13711.  
  13712.  
  13713.  /* PUBDOC START
  13714.   * ----------------------- Platform specific APIs -----------------------
  13715.   * PUBDOC END
  13716.   */
  13717.  
  13718.  /***************************** Public  Function ****************************\
  13719.  * PUBDOC START
  13720.  * HCONV EXPENTRY DdeConverseWithWindow(
  13721.  * HWND hwnd,            // server window to converse with
  13722.  * HSZ hszApp,           // app name to converse on
  13723.  * HSZ hszTopic,         // topic name to converse on
  13724.  * PCONVCONTEXT pCC)     // language information to converse on
  13725.  *
  13726.  * This creates a pre-initiated client conversation with the given hwnd.
  13727.  * The conversation is assumed to be on the given app, topic and context.
  13728.  * This is useful for implementing such things as drag and drop DDE
  13729.  * protocols.  hszApp and hszTopic cannot be NULL.  See
  13730.  * DdeCreateServerWindow().
  13731.  *
  13732.  * PUBDOC END
  13733.  \***************************************************************************/
  13734.  HCONV EXPENTRY DdeConverseWithWindow(hwnd, hszApp, hszTopic, pCC)
  13735.  HWND hwnd;
  13736.  HSZ hszApp, hszTopic;
  13737.  PCONVCONTEXT pCC;
  13738.  {
  13739.      PAPPINFO pai;
  13740.  
  13741.      UNUSED hwnd;
  13742.      UNUSED hszApp;
  13743.      UNUSED hszTopic;
  13744.      UNUSED pCC;
  13745.  
  13746.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  13747.          return(0);
  13748.  
  13749.      if (QuerylatomLength((LATOM)hszApp) == 0 ||
  13750.              QuerylatomLength((LATOM)hszTopic) == 0) {
  13751.          pai->LastError = DMGERR_INVALIDPARAMETER;
  13752.          return(0);
  13753.      }
  13754.  
  13755.  }
  13756.  
  13757.  
  13758.  /***************************** Public  Function ****************************\
  13759.  * PUBDOC START
  13760.  * HWND DdeCreateServerWindow(hszApp, hszTopic, pCC)
  13761.  * HSZ hszApp,       // app name to accept conversations on.
  13762.  * HSZ hszTopic;     // topic name to accept conversations on.
  13763.  * PCONVCONTEXT pCC; // language information to accept or NULL for sys default
  13764.  *
  13765.  * This creates a pre_initiated server DDE window for the caller.  The
  13766.  * server window does not know what client window it will be talking to.  As
  13767.  * soon as any DDE message is received by the DDE server window, its
  13768.  * companion client hwnd is remembered and the conversation is 'locked in'.
  13769.  * The hwnd of the server window is returned.  hszApp and hszTopic cannot
  13770.  * be NULL.
  13771.  *
  13772.  * Typically, the server app would call CreateServerWindow() and pass the
  13773.  * hwnd to some prospective client via some other transport mechanism.  The
  13774.  * client would then call ConverseWithWindow() with the hwnd it received
  13775.  * from the server and then begin DDE transactions using the HCONV returned.
  13776.  *
  13777.  * A server may pass this hwnd to many potential clients.  Only the first
  13778.  * one that responds would get 'locked in'.  The rest would be out of luck
  13779.  * and their API calls would fail.  The server window ignores messages that
  13780.  * to not fit the app and topic given.
  13781.  *
  13782.  * PUBDOC END
  13783.  \****************************************************************************
  13784.  HWND EXPENTRY DdeCreateServerWindow(hszApp, hszTopic, pCC)
  13785.  HSZ hszApp, hszTopic;
  13786.  PCONVCONTEXT pCC;
  13787.  {
  13788.      PAPPINFO pai;
  13789.      INITINFO ii;
  13790.      HWND hwndServer;
  13791.  
  13792.      hszApp;
  13793.      hszTopic;
  13794.      pCC;
  13795.  
  13796.      if ((pai = GetCurrentAppInfo(TRUE)) == NULL)
  13797.          return(0);
  13798.  
  13799.      if (QuerylatomLength((LATOM)hszApp) == 0 ||
  13800.              QuerylatomLength((LATOM)hszTopic) == 0) {
  13801.          pai->LastError = DMGERR_INVALIDPARAMETER;
  13802.          return(0);
  13803.      }
  13804.  
  13805.      if ((hwndServer = CreateServerWindow(pai, hszTopic)) == NULL)
  13806.          return(0);
  13807.  
  13808.      ii.hszAppName = hszApp;
  13809.      ii.hszTopic = hszTopic;
  13810.      ii.hwndSend =
  13811.      ii.hwndFrame = NULL;
  13812.      ii.pCC = pCC;
  13813.      WinSendMsg(hwndServer, UMSR_INITIATE, 0L, 0L);
  13814.  }
  13815.  
  13816.  
  13817.  DDESPY.C
  13818.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DDESPY\DDESPY.C
  13819.  
  13820.  /***************************** Module Header ******************************\
  13821.  * Module Name: ddespy
  13822.  *
  13823.  * This is a small DDE ddespyr which lets me see whats going on.
  13824.  *
  13825.  * Created:      sanfords
  13826.  *
  13827.  * Copyright (c) 1988, 1989  Microsoft Corporation
  13828.  \***************************************************************************/
  13829.  #include "ddespy.h"
  13830.  
  13831.  /*********** declares *********/
  13832.  
  13833.  HWND hwndExec = NULL;
  13834.  
  13835.  SWP gswp[IW_LAST - IW_FIRST + 1];
  13836.  PSZ apszTitles[] = {
  13837.          "Applications", "Topics", "System Items", "Data"
  13838.                     };
  13839.  
  13840.  
  13841.  PSZ apszType[] = {
  13842.                          "0-Type"        ,
  13843.                          "ACK"           ,
  13844.                          "ADVDATA"       ,
  13845.                          "ADVREQ"        ,
  13846.                          "ADVSTART"      ,
  13847.                          "ADVSTOP"       ,
  13848.                          "EXEC"          ,
  13849.                          "INIT"          ,
  13850.                          "INITCONF"      ,
  13851.                          "MONITOR"       ,
  13852.                          "PKT"           ,
  13853.                          "POKE"          ,
  13854.                          "REGISTER"      ,
  13855.                          "REQUEST"       ,
  13856.                          "RTNPKT"        ,
  13857.                          "TERM"          ,
  13858.                          "UNREGISTER"    ,
  13859.                          "WILDINIT"      ,
  13860.                          "XFERCOMP"      ,
  13861.                          "19"            ,
  13862.                          "20"            ,
  13863.                          "21"            ,
  13864.                          "22"            ,
  13865.                          "23"            ,
  13866.                          "24"            ,
  13867.                          "25"            ,
  13868.                          "26"            ,
  13869.                          "27"            ,
  13870.                          "28"            ,
  13871.                          "29"            ,
  13872.                          "30"            ,
  13873.                          "31"            ,
  13874.                 };
  13875.  
  13876.  PSZ apszState[] = {         /* corresponds to convinfo.usStatus */
  13877.                          "DISCONNECTED"      ,
  13878.                          "CONNECTED"         ,
  13879.                          "NOADVISE"          ,
  13880.                          "ADVISE"            ,
  13881.                    };
  13882.  
  13883.  PSZ apszStatus[] = {        /* corresponds to convionfi.usConvst */
  13884.                          "NOACTIVITY"    ,
  13885.                          "INCOMPLETE"    ,
  13886.                          "TERMINATED"    ,
  13887.                          "CONNECTED"     ,
  13888.                          "INITIATING"    ,
  13889.                          "REQSENT"       ,
  13890.                          "DATARCVD"      ,
  13891.                          "POKESENT"      ,
  13892.                          "POKEACKRCVD"   ,
  13893.                          "EXECSENT"      ,
  13894.                          "EXECACKRCVD"   ,
  13895.                          "ADVSENT"       ,
  13896.                          "UNADVSENT"     ,
  13897.                          "ADVACKRCVD"    ,
  13898.                          "UNADVACKRCVD"  ,
  13899.                          "ADVDATASENT"   ,
  13900.                          "ADVDATAACKRCVD",
  13901.                     };
  13902.  
  13903.  
  13904.  #define GetLBCount(hw) (SHORT)WinSendMsg((hw), LM_QUERYITEMCOUNT, 0L, 0L)
  13905.  #define GetLBSelectedItem(hw) \
  13906.              (SHORT)WinSendMsg((hw), LM_QUERYSELECTION, (MPARAM)LIT_FIRST, 0L)
  13907.  #define GetLBItemHandle(hw, i) \
  13908.              (ULONG)WinSendMsg((hw), LM_QUERYITEMHANDLE, (MPARAM)(i), 0L)
  13909.  #define GetLBItemText(hw, i, cch, psz) \
  13910.              (ULONG)WinSendMsg((hw), LM_QUERYITEMTEXT, MPFROM2SHORT((i),(cch))
  13911.  #define DeleteLBItem(hw, i) WinSendMsg(hw, LM_DELETEITEM, MPFROMSHORT(i), 0L)
  13912.  #define NotifyOwner(hwnd, msg, mp1, mp2) \
  13913.              (WinSendMsg(WinQueryWindow(hwnd, QW_OWNER, FALSE), msg, mp1, mp2)
  13914.  
  13915.  
  13916.  void cdecl main(int argc, char **argv);
  13917.  void ResizeChildren(USHORT cxNew, USHORT cyNew);
  13918.  HDMGDATA EXPENTRY dataxfer(HCONV hConv, HSZ hszTopic, HSZ hszItem,
  13919.          USHORT usFmt, USHORT usType, HDMGDATA hDmgData);
  13920.  MRESULT EXPENTRY ClientWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  13921.  MRESULT EXPENTRY GetTimeoutDlgProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM
  13922.  MRESULT EXPENTRY EnhancedEFWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM
  13923.  MRESULT EXPENTRY ExecDlgProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);
  13924.  void Refresh(void);
  13925.  SHORT InsertLBItem(HWND hwndLB, PSZ psz, ULONG ulHandle);
  13926.  void SetLBEntries(HCONV hConv, HSZ hszItem, USHORT iwlb);
  13927.  void UpdateQueue(HWND hwndCB, HCONV hConv);
  13928.  void ConvInfoToString(PCONVINFO pci, PSZ psz, USHORT cbMax);
  13929.  PSZ mylstrcat(PSZ psz1, PSZ psz2, PSZ pszLast);
  13930.  int lstrlen(PSZ psz);
  13931.  
  13932.  /************* GLOBAL VARIABLES  ************/
  13933.  
  13934.  HAB hab;
  13935.  HMQ hmq;
  13936.  HHEAP hheap;
  13937.  HWND hwndFrame;
  13938.  HWND hwndClient;
  13939.  USHORT cyTitles;
  13940.  USHORT cxBorder;
  13941.  HCONVLIST hConvListMain;
  13942.  HSZ hszSysTopic;
  13943.  HSZ hszSysItemTopics;
  13944.  HSZ hszSysItemSysItems;
  13945.  ULONG gTimeout = 1000L;
  13946.  PFNWP lpfnSysEFWndProc;
  13947.  
  13948.  void cdecl main(argc, argv)
  13949.  int argc;
  13950.  char **argv;
  13951.  {
  13952.      USHORT err;
  13953.      QMSG qmsg;
  13954.  
  13955.      argc; argv;
  13956.  
  13957.      hab = WinInitialize(0);
  13958.      hmq = WinCreateMsgQueue(hab, 0);
  13959.      hheap = WinCreateHeap(0, 0, 0, 0, 0, HM_MOVEABLE);
  13960.  
  13961.      if (!WinRegisterClass(hab, "DDESpyr Class", ClientWndProc, CS_SIZEREDRAW,
  13962.          goto abort;
  13963.  
  13964.      cyTitles = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
  13965.      cxBorder = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  13966.  
  13967.      hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, NULL,
  13968.              (PSZ)"DDESpyr Class",
  13969.              (PSZ)"", WS_VISIBLE, (HMODULE)NULL, IDR_MAIN,
  13970.              &hwndClient);
  13971.  
  13972.      WinSetWindowText(hwndFrame, "DDE Spy");
  13973.      if (err = DdeInitialize((PFNCALLBACK)dataxfer, 0L, 0L)) {
  13974.          DdePostError(err);
  13975.          goto abort;
  13976.      }
  13977.  
  13978.      hszSysTopic = DdeGetHsz((PSZ)SZDDESYS_TOPIC, 0, 0);
  13979.      hszSysItemTopics = DdeGetHsz((PSZ)SZDDESYS_ITEM_TOPICS, 0, 0);
  13980.      hszSysItemSysItems = DdeGetHsz((PSZ)SZDDESYS_ITEM_SYSITEMS, 0, 0);
  13981.  
  13982.      Refresh();
  13983.  
  13984.      while (WinGetMsg(hab, &qmsg, 0, 0, 0)) {
  13985.          WinDispatchMsg(hab, &qmsg);
  13986.      }
  13987.  
  13988.      DdeUninitialize();
  13989.  abort:
  13990.      if (hwndFrame)
  13991.          WinDestroyWindow(hwndFrame);
  13992.      if (hheap) {
  13993.          WinDestroyHeap(hheap);
  13994.      }
  13995.      WinTerminate(hab);
  13996.      DosExit(TRUE, 0);
  13997.  }
  13998.  
  13999.  
  14000.  MRESULT EXPENTRY ClientWndProc(hwnd, msg, mp1, mp2)
  14001.  HWND hwnd;
  14002.  USHORT msg;
  14003.  MPARAM mp1, mp2;
  14004.  {
  14005.      USHORT i;
  14006.  
  14007.      switch (msg) {
  14008.      case WM_CREATE:
  14009.          /*
  14010.           * initialize globals
  14011.           */
  14012.          hwndClient = hwnd;
  14013.          for (i = IW_APPSLBOX; i <= IW_ITEMSLBOX; i++) {
  14014.              gswp[i].hwnd = WinCreateWindow(hwndClient, WC_LISTBOX, "",
  14015.                      WS_VISIBLE | LS_NOADJUSTPOS, 0, 0, 0, 0, hwndClient,
  14016.                      HWND_TOP, i, NULL, NULL);
  14017.          }
  14018.          for (i = IW_APPSTITLE; i <= IW_DATATITLE; i++) {
  14019.              gswp[i].hwnd = WinCreateWindow(hwndClient, WC_STATIC,
  14020.                      apszTitles[i - IW_APPSTITLE],
  14021.                      WS_VISIBLE | SS_TEXT | DT_CENTER | DT_BOTTOM,
  14022.                      0, 0, 0, 0, hwndClient,
  14023.                      HWND_TOP, i, NULL, NULL);
  14024.          }
  14025.          gswp[IW_DATATEXT].hwnd = WinCreateWindow(hwndClient, WC_STATIC, "",
  14026.                  WS_VISIBLE | SS_TEXT | DT_WORDBREAK,
  14027.                  0, 0, 0, 0, hwndClient,
  14028.                  HWND_TOP, i, NULL, NULL);
  14029.  
  14030.          break;
  14031.  
  14032.      case WM_COMMAND:
  14033.          switch (LOUSHORT(mp1)) {
  14034.          case IDM_REFRESH:
  14035.              Refresh();
  14036.              break;
  14037.  
  14038.          case IDM_SETTIMEOUT:
  14039.              gTimeout = (USHORT)WinDlgBox(hwndFrame, NULL,
  14040.                      (PFNWP)GetTimeoutDlgProc,
  14041.                      (HMODULE)NULL, IDD_GETTIMEOUT, NULL);
  14042.              break;
  14043.  
  14044.          case IDM_EXEC:
  14045.              WinDlgBox(HWND_DESKTOP, hwnd, ExecDlgProc, NULL, IDD_EXEC, NULL);
  14046.              break;
  14047.          }
  14048.          break;
  14049.  
  14050.      case WM_CONTROL:
  14051.          switch (LOUSHORT(mp1)) {
  14052.          case IW_APPSLBOX:
  14053.              switch (HIUSHORT(mp1)) {
  14054.              case LN_SELECT:
  14055.                  hwnd = gswp[IW_APPSLBOX].hwnd;
  14056.                  SetLBEntries((HCONV)GetLBItemHandle(hwnd,
  14057.                          GetLBSelectedItem(hwnd)),
  14058.                          hszSysItemTopics, IW_TOPICSLBOX);
  14059.                  SetLBEntries((HCONV)GetLBItemHandle(hwnd,
  14060.                          GetLBSelectedItem(hwnd)),
  14061.                          hszSysItemSysItems, IW_ITEMSLBOX);
  14062.                  break;
  14063.              }
  14064.              break;
  14065.  
  14066.          case IW_TOPICSLBOX:
  14067.              break;
  14068.  
  14069.          case IW_ITEMSLBOX:
  14070.              break;
  14071.  
  14072.          default:
  14073.              goto DoDefAction;
  14074.          }
  14075.          break;
  14076.  
  14077.      case WM_SIZE:
  14078.          /*
  14079.           * resize children
  14080.           */
  14081.          ResizeChildren(SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
  14082.          break;
  14083.  
  14084.      case WM_ERASEBACKGROUND:
  14085.          return(TRUE);
  14086.          break;
  14087.  
  14088.      default:
  14089.  DoDefAction:
  14090.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  14091.      }
  14092.      return(0L);
  14093.  }
  14094.  
  14095.  
  14096.  
  14097.  void ResizeChildren(cxNew, cyNew)
  14098.  USHORT cxNew, cyNew;
  14099.  {
  14100.      USHORT i;
  14101.  
  14102.      for (i = IW_FIRST; i <= IW_LAST; i++) {
  14103.          gswp[i].fs = SWP_SIZE | SWP_MOVE | SWP_SHOW;
  14104.          gswp[i].hwndInsertBehind = HWND_TOP;
  14105.      }
  14106.  
  14107.      for (i = IW_APPSTITLE; i <= IW_ITEMSTITLE; i++) {
  14108.          gswp[i].x =
  14109.          gswp[i - IW_APPSTITLE + IW_APPSLBOX].x = i == IW_APPSTITLE ? -cxBorde
  14110.                  gswp[i - 1].x + gswp[i - 1].cx - cxBorder;
  14111.  
  14112.          gswp[i].y = cyNew - cyTitles;
  14113.          gswp[i - IW_APPSTITLE + IW_APPSLBOX].y = cyNew / 2;
  14114.  
  14115.          gswp[i].cx =
  14116.          gswp[i - IW_APPSTITLE + IW_APPSLBOX].cx = cxNew / 3;
  14117.  
  14118.          gswp[i].cy = cyTitles;
  14119.          gswp[i - IW_APPSTITLE + IW_APPSLBOX].cy = (cyNew / 2) - cyTitles;
  14120.      }
  14121.  
  14122.      gswp[IW_ITEMSLBOX].cx = cxNew - gswp[IW_ITEMSLBOX].x + cxBorder;
  14123.  
  14124.      gswp[IW_DATATITLE].cy = cyTitles;
  14125.      gswp[IW_DATATITLE].y =
  14126.      gswp[IW_DATATEXT].cy = cyNew / 2 - cyTitles;
  14127.  
  14128.      gswp[IW_DATATITLE].cx =
  14129.      gswp[IW_DATATEXT].cx = cxNew;
  14130.  
  14131.      WinSetMultWindowPos(hab, gswp, IW_DATATEXT - IW_APPSTITLE + 1);
  14132.  }
  14133.  
  14134.  
  14135.  void Refresh()
  14136.  {
  14137.      HCONV hConv;
  14138.      register NPSZ npszAppName;
  14139.      CONVINFO ci;
  14140.      USHORT cb;
  14141.  
  14142.      WinLockWindowUpdate(HWND_DESKTOP, gswp[IW_APPSLBOX].hwnd);
  14143.      WinSendMsg(gswp[IW_APPSLBOX].hwnd, LM_DELETEALL, 0L, 0L);
  14144.      WinSendMsg(gswp[IW_TOPICSLBOX].hwnd, LM_DELETEALL, 0L, 0L);
  14145.      WinSendMsg(gswp[IW_ITEMSLBOX].hwnd, LM_DELETEALL, 0L, 0L);
  14146.  
  14147.      hConvListMain = DdeBeginEnumServers(0L, hszSysTopic, hConvListMain, NULL,
  14148.      if (hConvListMain) {
  14149.          hConv = 0;
  14150.          while (hConv = DdeGetNextServer(hConvListMain, hConv)) {
  14151.              DdeQueryConvInfo(hConv, &ci, QID_SYNC);
  14152.              if (ci.hszAppPartner != 0) {
  14153.                  cb = DdeGetHszString(ci.hszAppPartner, NULL, 0L) + 1;
  14154.                  npszAppName = WinAllocMem(hheap, cb);
  14155.                  DdeGetHszString(ci.hszAppPartner, (PSZ)npszAppName, (ULONG)cb
  14156.                  InsertLBItem(gswp[IW_APPSLBOX].hwnd, (PSZ)npszAppName,
  14157.                          (ULONG)hConv);
  14158.                  WinFreeMem(hheap, npszAppName, cb);
  14159.              } else {
  14160.                  InsertLBItem(gswp[IW_APPSLBOX].hwnd, SZINDETERMINATE,
  14161.                          (ULONG)hConv);
  14162.              }
  14163.          }
  14164.      }
  14165.      WinLockWindowUpdate(HWND_DESKTOP, NULL);
  14166.  }
  14167.  
  14168.  
  14169.  SHORT InsertLBItem(hwndLB, psz, ulHandle)
  14170.  HWND hwndLB;
  14171.  PSZ psz;
  14172.  ULONG ulHandle;
  14173.  {
  14174.      SHORT ili;
  14175.  
  14176.      ili = (SHORT)WinSendMsg(hwndLB, LM_INSERTITEM, (MPARAM)LIT_SORTASCENDING,
  14177.              (MPARAM)psz);
  14178.      WinSendMsg(hwndLB, LM_SETITEMHANDLE, MPFROMSHORT(ili), (MPARAM)ulHandle);
  14179.      return(ili);
  14180.  }
  14181.  
  14182.  
  14183.  void SetLBEntries(hConv, hszItem, iwlb)
  14184.  HCONV hConv;
  14185.  HSZ hszItem;
  14186.  USHORT iwlb;
  14187.  {
  14188.      NPSZ npsz, npszT1, npszT2;
  14189.      BOOL fDone = 0;
  14190.      ULONG cb;
  14191.      HDMGDATA hDmgData;
  14192.  
  14193.      hDmgData = DdeClientXfer(0L, 0L, hConv, hszItem, DDEFMT_TEXT,
  14194.          XTYP_REQUEST, gTimeout, NULL);
  14195.  
  14196.      if (hDmgData == 0) {
  14197.          DdePostError(DdeGetLastError());
  14198.          return;
  14199.      }
  14200.  
  14201.      cb = DdeGetData(hDmgData, NULL, 0L, 0L);
  14202.      /*
  14203.       * BUG - may later want to handle the case for cb > 0xFFFF
  14204.       */
  14205.      npsz = WinAllocMem(hheap, (USHORT)cb);
  14206.      if (npsz == NULL) {
  14207.          DdePostError(DMGERR_MEMORY_ERROR);
  14208.          return;
  14209.      }
  14210.      if (DdeGetData(hDmgData, (PBYTE)npsz, cb, 0L) == 0) {
  14211.          DdePostError(DdeGetLastError());
  14212.          goto Exit;
  14213.      }
  14214.      npszT1 = npszT2 = npsz;
  14215.      WinLockWindowUpdate(HWND_DESKTOP, gswp[iwlb].hwnd);
  14216.      WinSendMsg(gswp[iwlb].hwnd, LM_DELETEALL, 0L, 0L);
  14217.      while (!fDone) {
  14218.          while (*npszT2 != '\t' && *npszT2 != '\0')
  14219.              npszT2++;
  14220.          if (*npszT2 == '\t') {
  14221.              *npszT2 = '\0';
  14222.              npszT2++;
  14223.          } else
  14224.              fDone = TRUE;
  14225.          InsertLBItem(gswp[iwlb].hwnd, (PSZ)npszT1,
  14226.                  (ULONG)DdeGetHsz(npszT1, 0, 0));
  14227.          npszT1 = npszT2;
  14228.      }
  14229.      WinLockWindowUpdate(HWND_DESKTOP, NULL);
  14230.  
  14231.  Exit:
  14232.      WinFreeMem(hheap, (NPBYTE)npsz, (USHORT)cb);
  14233.      return;
  14234.  }
  14235.  
  14236.  
  14237.  
  14238.  HDMGDATA EXPENTRY dataxfer(hConv, hszTopic, hszItem, usFmt, usType,
  14239.          hDmgData)
  14240.  HCONV hConv;
  14241.  HSZ hszTopic;
  14242.  HSZ hszItem;
  14243.  USHORT usFmt;
  14244.  USHORT usType;
  14245.  HDMGDATA hDmgData;
  14246.  {
  14247.      hConv; hszTopic; hszItem; usFmt; usType; hDmgData;
  14248.  
  14249.      switch (usType) {
  14250.      case XTYP_XFERCOMPLETE:
  14251.          if (hwndExec) {
  14252.              if (DdeCheckQueue(hConv, &hDmgData, (ULONG)hDmgData, 0L)) {
  14253.                  PSZ psz;
  14254.                  if (psz = (PSZ)DdeAccessData(hDmgData)) {
  14255.                      WinSetDlgItemText(hwndExec, IDEF_DATA, psz);
  14256.                      /*
  14257.                       * Free this data here.
  14258.                       */
  14259.                      DdeFreeData(hDmgData);
  14260.                  }
  14261.              }
  14262.          }
  14263.          break;
  14264.      }
  14265.      return(0);
  14266.  }
  14267.  
  14268.  
  14269.  MRESULT EXPENTRY GetTimeoutDlgProc(hwnd, msg, mp1, mp2)
  14270.  HWND hwnd;
  14271.  USHORT msg;
  14272.  MPARAM mp1;
  14273.  MPARAM mp2;
  14274.  {
  14275.      USHORT usValue;
  14276.  
  14277.      switch (msg) {
  14278.      case WM_INITDLG:
  14279.          /*
  14280.           * set up our entryfield to be enhanced.
  14281.           */
  14282.          WinSetDlgItemShort(hwnd, IDC_EF, (USHORT)gTimeout, FALSE);
  14283.          lpfnSysEFWndProc = WinSubclassWindow(WinWindowFromID(hwnd, IDC_EF),
  14284.                  EnhancedEFWndProc);
  14285.          break;
  14286.  
  14287.      case ENHAN_ENTER:
  14288.          /*
  14289.           * when the user hits the enter key, it will be passed from the
  14290.           * entryfield to here and we will use it as a signal to exit.
  14291.           */
  14292.          WinQueryDlgItemShort(hwnd, IDC_EF, &usValue, FALSE);
  14293.          WinDismissDlg(hwnd, usValue);
  14294.          break;
  14295.  
  14296.      default:
  14297.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  14298.          break;
  14299.      }
  14300.      return(0);
  14301.  }
  14302.  
  14303.  MRESULT EXPENTRY EnhancedEFWndProc(hwnd, msg, mp1, mp2)
  14304.  HWND hwnd;
  14305.  USHORT msg;
  14306.  MPARAM mp1;
  14307.  MPARAM mp2;
  14308.  {
  14309.      switch (msg) {
  14310.      case WM_CHAR:
  14311.          if (LOUSHORT(mp1) & KC_SCANCODE &&
  14312.                  LOUSHORT(mp1) & KC_KEYUP &&
  14313.                  /*---HACK ALERT!---*/
  14314.                  LOBYTE(LOUSHORT(mp2)) == 0x0d) {
  14315.              NotifyOwner(hwnd, ENHAN_ENTER,
  14316.                      (MPARAM)WinQueryWindowUShort(hwnd, QWS_ID), 0L);
  14317.          }
  14318.          break;
  14319.      }
  14320.      return(lpfnSysEFWndProc(hwnd, msg, mp1, mp2));
  14321.  }
  14322.  
  14323.  
  14324.  
  14325.  MRESULT EXPENTRY ExecDlgProc(hwnd, msg, mp1, mp2)
  14326.  HWND hwnd;
  14327.  USHORT msg;
  14328.  MPARAM mp1;
  14329.  MPARAM mp2;
  14330.  {
  14331.      static UCHAR szT[255];
  14332.      static HCONV hConv = NULL;
  14333.      register USHORT i;
  14334.      USHORT cb;
  14335.      register USHORT xtyp;
  14336.      HDMGDATA hDmgData;
  14337.      HSZ hszApp, hszItem, hszTopic;
  14338.      BOOL fAssync;
  14339.      ULONG xid;
  14340.  
  14341.      switch (msg) {
  14342.      case WM_INITDLG:
  14343.          hwndExec = hwnd;
  14344.          WinSendDlgItemMsg(hwnd, IDEF_DATA, EM_SETTEXTLIMIT, (MPARAM)MAX_QSTRI
  14345.          WinSendDlgItemMsg(hwnd, IDCB_QDATA, EM_SETTEXTLIMIT, (MPARAM)MAX_QSTR
  14346.          if ((i = GetLBSelectedItem(gswp[IW_APPSLBOX].hwnd)) != LIT_NONE) {
  14347.              GetLBItemText(gswp[IW_APPSLBOX].hwnd, i, 255, szT);
  14348.              WinSetDlgItemText(hwnd, IDEF_APP, szT);
  14349.          }
  14350.          if ((i = GetLBSelectedItem(gswp[IW_TOPICSLBOX].hwnd)) != LIT_NONE) {
  14351.              GetLBItemText(gswp[IW_TOPICSLBOX].hwnd, i, 255, szT);
  14352.              WinSetDlgItemText(hwnd, IDEF_TOPIC, szT);
  14353.          }
  14354.          if ((i = GetLBSelectedItem(gswp[IW_ITEMSLBOX].hwnd)) != LIT_NONE) {
  14355.              GetLBItemText(gswp[IW_ITEMSLBOX].hwnd, i, 255, szT);
  14356.              WinSetDlgItemText(hwnd, IDEF_ITEM, szT);
  14357.          }
  14358.          WinSendDlgItemMsg(hwnd, IDRB_REQUEST, BM_CLICK, 0L, 0L);
  14359.          break;
  14360.  
  14361.      case WM_CONTROL:
  14362.      case WM_COMMAND:
  14363.          switch (LOUSHORT(mp1)) {
  14364.          case MBID_CANCEL:
  14365.              if (hConv != NULL)
  14366.                  DdeDisconnect(hConv);
  14367.              hConv = NULL;
  14368.              WinDismissDlg(hwnd, 0);
  14369.              break;
  14370.  
  14371.          case IDC_QFLUSH:
  14372.              DdeCheckQueue(hConv, NULL, QID_NEWEST, CQ_FLUSH);
  14373.              WinSetDlgItemText(hwnd, IDCB_QDATA, "");
  14374.              UpdateQueue(WinWindowFromID(hwnd, IDCB_QDATA), hConv);
  14375.              break;
  14376.  
  14377.          case IDC_QUPDATE:
  14378.              UpdateQueue(WinWindowFromID(hwnd, IDCB_QDATA), hConv);
  14379.              WinSendDlgItemMsg(hwnd, IDCB_QDATA, CBM_SHOWLIST, (MPARAM)TRUE, 0
  14380.              break;
  14381.  
  14382.          case IDC_DOIT:
  14383.              i = (USHORT)WinSendDlgItemMsg(hwnd, IDRB_ADVSTART,
  14384.                      BM_QUERYCHECKINDEX, 0L, 0L) + IDRB_ADVSTART;
  14385.              WinQueryDlgItemText(hwnd, IDEF_APP, 255, szT);
  14386.              hszApp = DdeGetHsz(szT, 0, 0);
  14387.              WinQueryDlgItemText(hwnd, IDEF_TOPIC, 255, szT);
  14388.              hszTopic = DdeGetHsz(szT, 0, 0);
  14389.              WinQueryDlgItemText(hwnd, IDEF_ITEM, 255, szT);
  14390.              hszItem = DdeGetHsz(szT, 0, 0);
  14391.              if (i != IDRB_REQUEST) {
  14392.                  WinQueryDlgItemText(hwnd, IDEF_DATA, 255, szT);
  14393.                  cb = WinQueryDlgItemTextLength(hwnd, IDEF_DATA);
  14394.              }
  14395.              if (hConv == NULL && !(hConv = DdeConnect(hszApp, hszTopic, NULL,
  14396.                  DdePostError(DdeGetLastError());
  14397.                  if (LOUSHORT(mp1) == MBID_OK)
  14398.                      WinDismissDlg(hwnd, 0);
  14399.                  return(0);
  14400.              }
  14401.              switch (i) {
  14402.              case IDRB_REQUEST:
  14403.                  xtyp = XTYP_REQUEST;
  14404.                  goto XferOut;
  14405.                  break;
  14406.              case IDRB_ADVSTART:
  14407.                  xtyp = XTYP_ADVSTART;
  14408.                  goto XferOut;
  14409.                  break;
  14410.              case IDRB_ADVSTOP:
  14411.                  xtyp = XTYP_ADVSTOP;
  14412.                  goto XferOut;
  14413.                  break;
  14414.              case IDRB_POKE:
  14415.                  xtyp = XTYP_POKE;
  14416.                  goto XferOut;
  14417.                  break;
  14418.              case IDRB_EXECUTE:
  14419.                  xtyp = XTYP_EXEC;
  14420.  XferOut:
  14421.                  fAssync = (BOOL)WinSendDlgItemMsg(hwnd, IDCBX_ASSYNC,
  14422.                          BM_QUERYCHECK, 0L, 0L);
  14423.                  if (!(hDmgData = DdeClientXfer((PBYTE)szT, (ULONG)cb + 1,
  14424.                          hConv, hszItem, DDEFMT_TEXT, xtyp,
  14425.                          fAssync ? TIMEOUT_ASYNC : gTimeout, &xid)))
  14426.                      DdePostError(DdeGetLastError());
  14427.  
  14428.                  if (fAssync) {
  14429.                      UpdateQueue(WinWindowFromID(hwnd, IDCB_QDATA), hConv);
  14430.                  } else {
  14431.                      if (i == IDRB_REQUEST) {
  14432.                          DdeGetData(hDmgData, szT, 255L, 0L);
  14433.                          DdeFreeData(hDmgData);
  14434.                          WinSetWindowText(gswp[IW_DATATEXT].hwnd, szT);
  14435.                          WinSetDlgItemText(hwnd, IDEF_DATA, szT);
  14436.                      }
  14437.                  }
  14438.  
  14439.              }
  14440.              break;
  14441.          }
  14442.          break;
  14443.  
  14444.      case WM_DESTROY:
  14445.          hwndExec = NULL;
  14446.      default:
  14447.          return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  14448.          break;
  14449.      }
  14450.      return(0);
  14451.  }
  14452.  
  14453.  
  14454.  
  14455.  void UpdateQueue(hwndCB, hConv)
  14456.  HWND hwndCB;
  14457.  HCONV hConv;
  14458.  {
  14459.      SHORT lit;
  14460.      SHORT litSel = LIT_FIRST;
  14461.      CONVINFO ci;
  14462.      ULONG id, idSel;
  14463.      USHORT cItems;
  14464.      char szT[MAX_QSTRING];
  14465.  
  14466.      lit = (SHORT)WinSendMsg(hwndCB, LM_QUERYSELECTION,
  14467.              MPFROMSHORT(LIT_FIRST), 0L);
  14468.      idSel = (SHORT)WinSendMsg(hwndCB, LM_QUERYITEMHANDLE, MPFROMSHORT(lit), 0
  14469.      WinSendMsg(hwndCB, LM_DELETEALL, 0L, 0L);
  14470.      cItems = (USHORT)DdeCheckQueue(hConv, NULL, QID_NEWEST, CQ_COUNT);
  14471.      id = DdeCheckQueue(hConv, NULL, QID_NEWEST, 0L);
  14472.      while (cItems--) {
  14473.          DdeQueryConvInfo(hConv, &ci, id);
  14474.          ConvInfoToString(&ci, szT, MAX_QSTRING);
  14475.          lit = (SHORT)WinSendMsg(hwndCB, LM_INSERTITEM, MPFROMSHORT(LIT_END),
  14476.          WinSendMsg(hwndCB, LM_SETITEMHANDLE, MPFROMSHORT(lit), (MPARAM)id);
  14477.          if (id == idSel)
  14478.              litSel = lit;
  14479.          id = DdeCheckQueue(hConv, NULL, id, CQ_NEXT);
  14480.      }
  14481.      WinSendMsg(hwndCB, LM_SELECTITEM, MPFROMSHORT(litSel), (MPARAM)TRUE);
  14482.  }
  14483.  
  14484.  
  14485.  
  14486.  void ConvInfoToString(pci, psz, cbMax)
  14487.  PCONVINFO pci;
  14488.  PSZ psz;
  14489.  USHORT cbMax;
  14490.  {
  14491.      PSZ pszLast;
  14492.      char szT[100];
  14493.  
  14494.      pszLast = psz + cbMax - 1;
  14495.      *psz = '\0';
  14496.      psz = mylstrcat(psz, apszType[(pci->usType >> 4) && 0x1F], pszLast);
  14497.      psz = mylstrcat(psz, ": ", pszLast);
  14498.      psz = mylstrcat(psz, apszState[pci->usStatus & ST_CONNECTED ? 1 : 0], psz
  14499.      psz = mylstrcat(psz, " ", pszLast);
  14500.      psz = mylstrcat(psz, apszState[pci->usStatus & ST_ADVISE ? 3 : 2], pszLas
  14501.      psz = mylstrcat(psz, " ", pszLast);
  14502.      psz = mylstrcat(psz, apszStatus[pci->usConvst], pszLast);
  14503.      psz = mylstrcat(psz, " ", pszLast);
  14504.      if (pci->usFmt == DDEFMT_TEXT) {
  14505.          psz = mylstrcat(psz, "TEXT", pszLast);
  14506.      } else {
  14507.          DdeGetHszString(pci->hszItem, szT, 100L);
  14508.          psz = mylstrcat(psz, szT, pszLast);
  14509.      }
  14510.      psz = mylstrcat(psz, " ", pszLast);
  14511.      DdeGetHszString(pci->hszItem, szT, 100L);
  14512.      psz = mylstrcat(psz, szT, pszLast);
  14513.  
  14514.      if (pci->LastError) {
  14515.          psz = mylstrcat(psz, " ", pszLast);
  14516.          DdeGetErrorString(pci->LastError, pszLast - psz, psz);
  14517.      }
  14518.      pszLast = '\0';
  14519.  }
  14520.  
  14521.  
  14522.  /***************************** Public  Function ****************************\
  14523.  * Concatonates psz1 and psz2 into psz1.
  14524.  * returns psz pointing to end of concatonated string.
  14525.  * pszLast marks point at which copying must stop.  This makes this operation
  14526.  * safe for limited buffer sizes.
  14527.  *
  14528.  * History:  1/1/89  created sanfords
  14529.  \***************************************************************************/
  14530.  PSZ mylstrcat(psz1, psz2, pszLast)
  14531.  PSZ psz1, psz2, pszLast;
  14532.  {
  14533.      psz1 += lstrlen(psz1);
  14534.      while (*psz2 != '\0' && psz1 < pszLast) {
  14535.          *psz1++ = *psz2++;
  14536.      }
  14537.      *psz1 = '\0';
  14538.      return(psz1);
  14539.  }
  14540.  
  14541.  
  14542.  /***************************** Private Function ****************************\
  14543.  *
  14544.  * returns string length not counting null terminator.
  14545.  *
  14546.  * History:  1/1/89  created     sanfords
  14547.  \***************************************************************************/
  14548.  int lstrlen(psz)
  14549.  PSZ psz;
  14550.  {
  14551.      int c = 0;
  14552.  
  14553.      while (*psz != 0) {
  14554.          psz++;
  14555.          c++;
  14556.      }
  14557.      return(c);
  14558.  }
  14559.  
  14560.  
  14561.  
  14562.  DEMO.C
  14563.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DEMO\DEMO.C
  14564.  
  14565.  /****************************** Module Header ******************************\
  14566.  * Module Name:  demo.c - Demo application
  14567.  *
  14568.  * Created:
  14569.  *
  14570.  * Copyright (c) 1987  Microsoft Corporation
  14571.  *
  14572.  \***************************************************************************/
  14573.  
  14574.  #include "demo.h"
  14575.  #include <stdlib.h>
  14576.  
  14577.  /************* GLOBAL VARIABLES         */
  14578.  
  14579.  char szDemoClass[] = "Demo";
  14580.  
  14581.  HAB  hab;
  14582.  HMQ  hmqDemo;
  14583.  HWND hwndDemo;
  14584.  HWND hwndDemoFrame;
  14585.  HCONV hconv = NULL;
  14586.  HSZ hszTitle, hszTopicChase, hszItemPos;
  14587.  USHORT fmtSWP;
  14588.  SWP SWPTarget = { 0 };
  14589.  PFNWP RealFrameProc;
  14590.  BOOL flee = FALSE;
  14591.  USHORT cServers = 0;
  14592.  USHORT cxScreen, cyScreen;
  14593.  
  14594.  #define TIMEOUT 100
  14595.  #define TIMERSPEED 1000
  14596.  
  14597.  /**************************************/
  14598.  
  14599.  VOID CommandMsg(USHORT cmd)
  14600.  {
  14601.      UNUSED cmd;
  14602.  }
  14603.  
  14604.  BOOL DemoInit()
  14605.  {
  14606.      hab = WinInitialize(0);
  14607.  
  14608.      hmqDemo = WinCreateMsgQueue(hab, 0);
  14609.  
  14610.      cxScreen = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  14611.      cyScreen = (USHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  14612.      srand(2);
  14613.  
  14614.      if (!WinRegisterClass(hab, szDemoClass, (PFNWP)DemoWndProc,
  14615.              CS_SIZEREDRAW, 0))
  14616.           return(FALSE);
  14617.  
  14618.      /*
  14619.       * Initialize the ddeml
  14620.       */
  14621.      if (DdeInitialize((PFNCALLBACK)callback, 0L, 0L))
  14622.          return(FALSE);
  14623.  
  14624.      /*
  14625.       * Now create HSZs for each of our DDE strings.
  14626.       */
  14627.      fmtSWP = WinAddAtom(WinQuerySystemAtomTable(), "SWP FORMAT");
  14628.      hszTitle = DdeGetHsz("Demo", 0, 0);
  14629.      hszTopicChase = DdeGetHsz("Chaser", 0, 0);
  14630.      hszItemPos = DdeGetHsz("Position", 0, 0);
  14631.  
  14632.      /*
  14633.       * let others know we are here - available as a server and turn on
  14634.       * filtering so we don't get bothered with any initiates for any
  14635.       * other app names.
  14636.       */
  14637.      DdeAppNameServer(hszTitle, ANS_REGISTER | ANS_FILTERON);
  14638.  
  14639.      return(TRUE);
  14640.  }
  14641.  
  14642.  int cdecl main(int argc, char** argv)
  14643.  {
  14644.      ULONG fcf;
  14645.      QMSG qmsg;
  14646.  
  14647.      UNUSED argc;
  14648.      UNUSED argv;
  14649.  
  14650.      if (!DemoInit()) {
  14651.          WinAlarm(HWND_DESKTOP, WA_ERROR);
  14652.          return(0);
  14653.      }
  14654.  
  14655.      fcf = FCF_STANDARD;
  14656.  
  14657.      hwndDemoFrame = WinCreateStdWindow(
  14658.              HWND_DESKTOP,
  14659.              WS_VISIBLE,
  14660.              &fcf,
  14661.              szDemoClass,
  14662.              "",
  14663.              WS_VISIBLE,
  14664.              NULL,
  14665.              IDR_DEMO,
  14666.              &hwndDemo);
  14667.  
  14668.      WinSetFocus(HWND_DESKTOP, hwndDemo);
  14669.  
  14670.      while (WinGetMsg(hab, (PQMSG)&qmsg, NULL, 0, 0)) {
  14671.          WinDispatchMsg(hab, (PQMSG)&qmsg);
  14672.      }
  14673.  
  14674.      WinDestroyWindow(hwndDemoFrame);
  14675.  
  14676.      WinDestroyMsgQueue(hmqDemo);
  14677.      WinTerminate(hab);
  14678.  
  14679.      return(0);
  14680.  }
  14681.  
  14682.  /********** Demo Window Procedure **************/
  14683.  
  14684.  MRESULT FAR PASCAL DemoWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  14685.  {
  14686.      HPS   hps;
  14687.      RECTL rclPaint;
  14688.      SWP swp;
  14689.      SHORT speed;
  14690.  
  14691.      switch (msg) {
  14692.      case WM_CREATE:
  14693.          /* Set up this global first thing in case we need it elsewhere */
  14694.          hwndDemo = hwnd;
  14695.          hwndDemoFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  14696.          RealFrameProc = WinSubclassWindow(hwndDemoFrame, DemoFrameWndProc);
  14697.          WinSetWindowPos(hwndDemoFrame, NULL, 0, 0, 0, 0, SWP_MINIMIZE | SWP_S
  14698.          /*
  14699.           * start the timer so we will keep looking for another app like ours
  14700.           * to chase.
  14701.           */
  14702.          WinStartTimer(hab, hwndDemo, 1, TIMERSPEED);
  14703.          return(MRFROMSHORT(FALSE));
  14704.          break;
  14705.  
  14706.      case WM_TIMER:
  14707.          /*
  14708.           * We use a timer to keep us moving.
  14709.           */
  14710.          if (!hconv) {
  14711.              HDMGDATA hData;
  14712.              PHSZHAPP phszhapp;
  14713.              /*
  14714.               * no active conversation, try to make one.
  14715.               */
  14716.              WinStopTimer(hab, hwndDemo, 1);
  14717.              /*
  14718.               * find out if any others like us are out there
  14719.               */
  14720.              hData = DdeAppNameServer(hszTitle, ANS_QUERYALLBUTME);
  14721.              if (!hData) {
  14722.                  /*
  14723.                   * wait till others arrive.
  14724.                   */
  14725.                  return(0);
  14726.              }
  14727.              /*
  14728.               * extract the first hApp from the hData so we can connect to it
  14729.               */
  14730.              phszhapp = (PHSZHAPP)DdeAccessData(hData);
  14731.              if (phszhapp->hsz == 0) {
  14732.                  DdeFreeData(hData);
  14733.                  return(0);
  14734.              }
  14735.              /*
  14736.               * perform directed connection to our target
  14737.               */
  14738.              hconv = DdeConnect(hszTitle, hszTopicChase, NULL, phszhapp->hApp)
  14739.              /*
  14740.               * free the hData now that we are done using it.
  14741.               */
  14742.              DdeFreeData(hData);
  14743.              WinStartTimer(hab, hwndDemo, 1, TIMERSPEED);
  14744.              if (!hconv) {
  14745.                  /*
  14746.                   * cant make one, try again later.
  14747.                   */
  14748.                  return(0);
  14749.              }
  14750.              /*
  14751.               * Get the target's position into SWPTarget.
  14752.               */
  14753.              if (hData = DdeClientXfer(NULL, 0L, hconv, hszItemPos, fmtSWP,
  14754.                      XTYP_REQUEST, TIMEOUT, NULL)) {
  14755.                  DdeCopyBlock(DdeAccessData(hData), (PBYTE)&SWPTarget,
  14756.                          sizeof(SWP));
  14757.                  DdeFreeData(hData);
  14758.              }
  14759.              /*
  14760.               * set up an advise loop so our moving target keeps us informed
  14761.               * of where he is.
  14762.               */
  14763.              DdeClientXfer(NULL, 0L, hconv, hszItemPos, fmtSWP,
  14764.                      XTYP_ADVSTART, TIMEOUT, NULL);
  14765.          }
  14766.  
  14767.          if (WinIsWindow(hab, SWPTarget.hwnd)) {
  14768.              /*
  14769.               * target data must be valid, move toward it.
  14770.               */
  14771.              speed = 1;
  14772.              WinQueryWindowPos(hwndDemoFrame, &swp);
  14773.              if (swp.x > SWPTarget.x)
  14774.                  swp.x -= speed;
  14775.              if (swp.x < SWPTarget.x)
  14776.                  swp.x += speed;
  14777.              if (swp.y > SWPTarget.y)
  14778.                  swp.y -= speed;
  14779.              if (swp.y < SWPTarget.y)
  14780.                  swp.y += speed;
  14781.              swp.fs = SWP_MOVE | SWP_NOADJUST;
  14782.              WinSetMultWindowPos(hab, &swp, 1);
  14783.              if ((swp.x == SWPTarget.x) && (swp.y == SWPTarget.y) && (!flee))
  14784.                  /*
  14785.                   * he's cought stop chasing him and go find another.
  14786.                   */
  14787.                  WinAlarm(HWND_DESKTOP, WA_NOTE);
  14788.                  DdeDisconnect(hconv);
  14789.                  hconv = NULL;
  14790.                  /*
  14791.                   * move to a random position
  14792.                   */
  14793.                  WinSetWindowPos(hwndDemoFrame, HWND_TOP, rand() % cxScreen,
  14794.                          rand() % cyScreen, 0, 0,
  14795.                          SWP_MOVE | SWP_ZORDER | SWP_NOADJUST);
  14796.              }
  14797.          } else if (hconv) {
  14798.              /*
  14799.               * Target is invalid, disconnect and try a reconnect later.
  14800.               */
  14801.              DdeDisconnect(hconv);
  14802.              hconv = NULL;
  14803.          }
  14804.          break;
  14805.  
  14806.      case WM_PAINT:
  14807.          hps = WinBeginPaint(hwnd, (HPS)NULL, &rclPaint);
  14808.          DemoPaint(hwnd, hps, &rclPaint);
  14809.          WinEndPaint(hps);
  14810.          break;
  14811.  
  14812.      case WM_COMMAND:
  14813.          CommandMsg(LOUSHORT(mp1));
  14814.          break;
  14815.  
  14816.      default:
  14817.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  14818.          break;
  14819.      }
  14820.      return(0L);
  14821.  }
  14822.  
  14823.  
  14824.  
  14825.  MRESULT FAR PASCAL DemoFrameWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM
  14826.  {
  14827.      switch (msg) {
  14828.      case WM_MOVE:
  14829.          DdePostAdvise(hszTopicChase, hszItemPos);
  14830.          /* fall through */
  14831.      default:
  14832.          return(RealFrameProc(hwnd, msg, mp1, mp2));
  14833.          break;
  14834.      }
  14835.      return(0L);
  14836.  }
  14837.  
  14838.  
  14839.  VOID DemoPaint(HWND hwnd, HPS hps, RECTL* prcl)
  14840.  {
  14841.      RECTL rcl;
  14842.  
  14843.      UNUSED prcl;
  14844.  
  14845.      /* get window interior rect */
  14846.      WinQueryWindowRect(hwnd, &rcl);
  14847.  
  14848.      /* print "Hello World" centered horizontally and vertically */
  14849.      WinDrawText(hps, -1, "Hello World", &rcl, SYSCLR_WINDOWTEXT,
  14850.              SYSCLR_WINDOW, DT_CENTER | DT_VCENTER | DT_ERASERECT);
  14851.  
  14852.      /* draw interior border */
  14853.      WinDrawBorder(hps, &rcl, 6, 6, SYSCLR_WINDOWTEXT, SYSCLR_WINDOW,
  14854.              DB_STANDARD);
  14855.  }
  14856.  
  14857.  
  14858.  
  14859.  HDMGDATA EXPENTRY callback(
  14860.  HCONV hConv,
  14861.  HSZ hszTopic,
  14862.  HSZ hszItem,
  14863.  USHORT usFmt,
  14864.  USHORT usType,
  14865.  HDMGDATA hDmgData)
  14866.  {
  14867.      SWP swp;
  14868.  
  14869.      UNUSED hConv;
  14870.  
  14871.      if (usType == XTYP_REGISTER && hszItem == hszTitle && !hconv) {
  14872.          /*
  14873.           * someone else came onboard, if we are looking for a target,
  14874.           * restart our clock.
  14875.           */
  14876.          WinStartTimer(hab, hwndDemo, 1, TIMERSPEED);
  14877.      }
  14878.  
  14879.      /*
  14880.       * we only care about stuff on our topic.
  14881.       */
  14882.      if (hszTopic != hszTopicChase)
  14883.          return(0);
  14884.  
  14885.      switch (usType) {
  14886.  
  14887.      case XTYP_ADVSTART:
  14888.          /*
  14889.           * Always allow advises on our item
  14890.           */
  14891.          return(hszItem == hszItemPos);
  14892.          break;
  14893.  
  14894.      case XTYP_ADVDATA:
  14895.          /*
  14896.           * Always accept advise data on our target's latest position.
  14897.           */
  14898.          if (hszItem == hszItemPos)
  14899.              DdeGetData(hDmgData, (PBYTE)&SWPTarget, sizeof(SWP), 0L);
  14900.          DdeFreeData(hDmgData);
  14901.          return(0);
  14902.          break;
  14903.  
  14904.      case XTYP_INIT:
  14905.          /*
  14906.           * always allow others to initiate with us on our topic.
  14907.           */
  14908.          return(hszItem == hszTitle && hszTopic == hszTopicChase);
  14909.          break;
  14910.  
  14911.      case XTYP_REQUEST:
  14912.      case XTYP_ADVREQ:
  14913.          /*
  14914.           * Respond to data requests as to our whereabouts item and format are
  14915.           * ok.
  14916.           */
  14917.          if (hszItem != hszItemPos || usFmt != fmtSWP)
  14918.              return(0);
  14919.          WinQueryWindowPos(hwndDemoFrame, &swp);
  14920.          return(DdePutData((PBYTE)&swp, sizeof(SWP), 0L, hszItemPos, fmtSWP, 0
  14921.          break;
  14922.  
  14923.      default:
  14924.          return(0);
  14925.      }
  14926.  }
  14927.  
  14928.  
  14929.  
  14930.  
  14931.  
  14932.  DIALOGS.C
  14933.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CLOCK\DIALOGS.C
  14934.  
  14935.  /*
  14936.      dialogs.c                Dialog procedures for PM Clock Application
  14937.  
  14938.      Created by Microsoft Corporation, 1989
  14939.  */
  14940.  #define INCL_WINDIALOGS
  14941.  #define INCL_WINBUTTONS
  14942.  #define INCL_WINSYS
  14943.  #include <os2def.h>
  14944.  #include <pmwin.h>
  14945.  #include "dialogs.h"
  14946.  
  14947.  /* defined in paint.c */
  14948.  extern USHORT usMajorTickPref ;
  14949.  extern USHORT usMinorTickPref ;
  14950.  extern LONG clrBackground ;
  14951.  extern LONG clrFace ;
  14952.  extern LONG clrHourHand ;
  14953.  extern LONG clrMinuteHand ;
  14954.  
  14955.  /* defined in clock.c */
  14956.  extern HWND hwndFrame ;
  14957.  
  14958.  /*
  14959.      ClkAboutDlgProc()                 "About..." dialog
  14960.  
  14961.      Returns:        MRESULT, 0 or return value from WinDefDlgProc
  14962.  */
  14963.  MRESULT EXPENTRY ClkAboutDlgProc ( HWND hwnd , USHORT usMsg ,
  14964.                                     MPARAM mp1 , MPARAM mp2 )
  14965.  {
  14966.      if ( usMsg == WM_COMMAND ) {
  14967.          WinDismissDlg ( hwnd , TRUE ) ;
  14968.          return 0L ;
  14969.      }
  14970.      else return WinDefDlgProc ( hwnd , usMsg , mp1 , mp2 ) ;
  14971.  }
  14972.  
  14973.  
  14974.  /*
  14975.      ClkTicksDlgProc()                "Ticks..." dialog
  14976.  
  14977.      Returns: MRESULT, 0 or return value from WinDefDlgProc
  14978.  */
  14979.  MRESULT EXPENTRY ClkTicksDlgProc ( HWND hwnd , USHORT usMsg ,
  14980.                                     MPARAM mp1 , MPARAM mp2 )
  14981.  {
  14982.      static USHORT usMajorTickSel ;
  14983.      static USHORT usMinorTickSel ;
  14984.      USHORT usButtonID ;
  14985.  
  14986.      switch ( usMsg ) {
  14987.  
  14988.          case WM_INITDLG :
  14989.  
  14990.              /* show the current major tick preference */
  14991.              WinSendMsg ( WinWindowFromID ( hwnd ,
  14992.                                             CLKTM_MAJOR | usMajorTickPref ) ,
  14993.                           BM_SETCHECK , MPFROM2SHORT ( TRUE , NULL ) , NULL )
  14994.  
  14995.              /* show the current minor tick preference */
  14996.              WinSendMsg ( WinWindowFromID ( hwnd ,
  14997.                                             CLKTM_MINOR | usMinorTickPref ) ,
  14998.                           BM_SETCHECK , MPFROM2SHORT ( TRUE , NULL ) , NULL )
  14999.  
  15000.              /* load the selection values from the preferences */
  15001.              usMajorTickSel = usMajorTickPref ;
  15002.              usMinorTickSel = usMinorTickPref ;
  15003.  
  15004.              /* let the default dialog procedure handle anything else */
  15005.              break ;
  15006.  
  15007.          case WM_COMMAND :
  15008.  
  15009.              switch ( LOUSHORT ( mp1 ) ) {
  15010.  
  15011.                  case DID_OK :
  15012.  
  15013.                      /* store away selections as preferences */
  15014.                      usMajorTickPref = usMajorTickSel ;
  15015.                      usMinorTickPref = usMinorTickSel ;
  15016.  
  15017.                      /* repaint with the new preferences */
  15018.                      WinInvalidateRect ( hwndFrame , NULL, TRUE ) ;
  15019.  
  15020.                  case DID_CANCEL :
  15021.                      WinDismissDlg ( hwnd , TRUE ) ;
  15022.              }
  15023.  
  15024.              return NULL ;
  15025.  
  15026.          case WM_CONTROL :
  15027.  
  15028.              if ( SHORT2FROMMP ( mp1 ) == BN_CLICKED ) {
  15029.  
  15030.                  usButtonID = SHORT1FROMMP ( mp1 ) ;
  15031.  
  15032.                  switch ( usButtonID & 0xff00 ) {
  15033.  
  15034.                      case CLKTM_MAJOR :
  15035.                          usMajorTickSel = LOBYTE ( usButtonID ) ;
  15036.                          break ;
  15037.  
  15038.                      case CLKTM_MINOR :
  15039.                          usMinorTickSel = LOBYTE ( usButtonID ) ;
  15040.                          break ;
  15041.                  }
  15042.              }
  15043.  
  15044.              /* fall through to the default control processing */
  15045.      }
  15046.  
  15047.      return WinDefDlgProc ( hwnd , usMsg , mp1 , mp2 ) ;
  15048.  }
  15049.  
  15050.  
  15051.  /*
  15052.      ClkColorsDlgProc()                "Clock Color Preferences" Dialog
  15053.  
  15054.      Returns: MRESULT, 0 or return value from WinDefDlgProc
  15055.  */
  15056.  MRESULT EXPENTRY ClkColorsDlgProc ( HWND hwnd , USHORT usMsg ,
  15057.                                     MPARAM mp1 , MPARAM mp2 )
  15058.  {
  15059.      USHORT usButtonID ;
  15060.      static USHORT usCheckedButtonID ;
  15061.      HWND hwndButton ;
  15062.      RECTL rclButton , rclButtonInterior ;
  15063.      static LONG clrBackgroundNew ;
  15064.      static LONG clrFaceNew ;
  15065.      static LONG clrHourHandNew ;
  15066.      static LONG clrMinuteHandNew ;
  15067.      static LONG * pclrNew ;
  15068.  
  15069.      switch ( usMsg ) {
  15070.  
  15071.          case WM_INITDLG :
  15072.  
  15073.              /* load the new values from the current ones */
  15074.              clrBackgroundNew = clrBackground ;
  15075.              clrFaceNew = clrFace ;
  15076.              clrHourHandNew = clrHourHand ;
  15077.              clrMinuteHandNew = clrMinuteHand ;
  15078.  
  15079.              /* click the "Background" radio button */
  15080.              WinSendMsg ( WinWindowFromID ( hwnd , CLKCLR_BACKGROUND ) ,
  15081.                           BM_CLICK , MPFROMSHORT ( TRUE ) , NULL ) ;
  15082.  
  15083.              /* let the default dialog procedure handle anything else */
  15084.              break ;
  15085.  
  15086.          case WM_COMMAND :
  15087.  
  15088.              switch ( LOUSHORT ( mp1 ) ) {
  15089.                  case DID_OK :
  15090.  
  15091.                      /* store the new values */
  15092.                      clrBackground = clrBackgroundNew ;
  15093.                      clrFace = clrFaceNew ;
  15094.                      clrHourHand = clrHourHandNew ;
  15095.                      clrMinuteHand = clrMinuteHandNew ;
  15096.  
  15097.                      /* repaint with the new colors */
  15098.                      WinInvalidateRect ( hwndFrame , NULL, TRUE ) ;
  15099.  
  15100.                  case DID_CANCEL :
  15101.  
  15102.                      WinDismissDlg ( hwnd , TRUE ) ;
  15103.              }
  15104.              return NULL ;
  15105.  
  15106.          case WM_CONTROL :
  15107.  
  15108.              usButtonID = SHORT1FROMMP ( mp1 ) ;
  15109.  
  15110.              /* selecting a new object */
  15111.              if ( usButtonID & CLKCLR_OBJECTS ) {
  15112.  
  15113.                  switch ( usButtonID ) {
  15114.                      case CLKCLR_BACKGROUND :
  15115.                          pclrNew = & clrBackgroundNew ;
  15116.                          break ;
  15117.                      case CLKCLR_FACE :
  15118.                          pclrNew = & clrFaceNew ;
  15119.                          break ;
  15120.                      case CLKCLR_HOURHAND :
  15121.                          pclrNew = & clrHourHandNew ;
  15122.                          break ;
  15123.                      case CLKCLR_MINUTEHAND :
  15124.                          pclrNew = & clrMinuteHandNew ;
  15125.                  }
  15126.  
  15127.                  /* click the button for the new object's current color */
  15128.                  WinSendMsg (
  15129.                      WinWindowFromID ( hwnd ,
  15130.                          CLKCLR_BUTTONSHIFT + ( USHORT ) * pclrNew ) ,
  15131.                      BM_CLICK , MPFROMSHORT ( TRUE ) , NULL ) ;
  15132.  
  15133.                  break ;
  15134.              }
  15135.  
  15136.              switch ( SHORT2FROMMP ( mp1 ) ) {
  15137.  
  15138.                  case BN_CLICKED :
  15139.  
  15140.                      * pclrNew = ( LONG ) usButtonID - CLKCLR_BUTTONSHIFT ;
  15141.  
  15142.                      /* turn off the check state of the previously checked
  15143.                       * button and turn on the check state of the button
  15144.                       * just clicked */
  15145.  
  15146.                      WinSendMsg ( WinWindowFromID ( hwnd , usCheckedButtonID )
  15147.                                   BM_SETCHECK , MPFROM2SHORT ( FALSE , NULL )
  15148.                                   NULL ) ;
  15149.                      WinSendMsg ( WinWindowFromID ( hwnd , usButtonID ) ,
  15150.                                   BM_SETCHECK , MPFROM2SHORT ( TRUE , NULL ) ,
  15151.                                   NULL ) ;
  15152.  
  15153.                      usCheckedButtonID = usButtonID ;
  15154.  
  15155.                      break ;
  15156.  
  15157.                  case BN_PAINT :
  15158.  
  15159.                      /* fill only the interior of the button, so we don't
  15160.                       * conflict with the focus indicator */
  15161.  
  15162.                      hwndButton = ( ( PUSERBUTTON ) mp2 ) -> hwnd ;
  15163.                      WinQueryWindowRect ( hwndButton , & rclButton ) ;
  15164.                      rclButton . xLeft ++ ;
  15165.                      rclButton . yBottom ++ ;
  15166.                      rclButton . xRight -- ;
  15167.                      rclButton . yTop -- ;
  15168.                      WinFillRect ( ( ( PUSERBUTTON ) mp2 ) -> hps ,
  15169.                                    & rclButton ,
  15170.                                    ( LONG ) usButtonID - CLKCLR_BUTTONSHIFT )
  15171.  
  15172.                      /* hollow out those buttons which aren't checked */
  15173.                      if ( ! WinSendMsg ( WinWindowFromID ( hwnd , usButtonID )
  15174.                                        BM_QUERYCHECK , NULL , NULL ) ) {
  15175.                          rclButtonInterior . xLeft = rclButton . xLeft + 4 ;
  15176.                          rclButtonInterior . yBottom = rclButton . yBottom + 4
  15177.                          rclButtonInterior . xRight = rclButton . xRight - 4 ;
  15178.                          rclButtonInterior . yTop = rclButton . yTop - 4 ;
  15179.                          WinFillRect ( ( ( PUSERBUTTON ) mp2 ) -> hps ,
  15180.                                        & rclButtonInterior , SYSCLR_WINDOW ) ;
  15181.                      }
  15182.  
  15183.                      break ;
  15184.              }
  15185.  
  15186.              /* fall through to the default control processing */
  15187.      }
  15188.  
  15189.      return WinDefDlgProc ( hwnd , usMsg , mp1 , mp2 ) ;
  15190.  }
  15191.  
  15192.  
  15193.  DLGPROC.C
  15194.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\INIEDIT\DLGPROC.C
  15195.  
  15196.  /******************************* Module Header ******************************
  15197.  * Module Name: DlgProc.c
  15198.  *
  15199.  * Created by Microsoft Corporation, 1989
  15200.  *
  15201.  *
  15202.  * System Test Application
  15203.  *
  15204.  *
  15205.  \***************************************************************************/
  15206.  
  15207.  
  15208.  #define LINT_ARGS                           // Include needed parts of PM
  15209.  #define INCL_WININPUT                       //    definitions
  15210.  #define INCL_WINSYS
  15211.  #define INCL_WINMESSAGEMGR
  15212.  #define INCL_WINBUTTONS
  15213.  #define INCL_WINPOINTERS
  15214.  #define INCL_WINHEAP
  15215.  #define INCL_WINSHELLDATA
  15216.  #define INCL_WINMENUS
  15217.  #define INCL_WINFRAMEMGR
  15218.  #define INCL_WINLISTBOXES
  15219.  #define INCL_WINENTRYFIELDS
  15220.  #define INCL_WINDIALOGS
  15221.  #define INCL_GPIBITMAPS
  15222.  #define INCL_GPIREGIONS
  15223.  #define INCL_GPILCIDS
  15224.  #define INCL_GPIPRIMITIVES
  15225.  #define INCL_DEV
  15226.  
  15227.  #include <string.h>
  15228.  #include <stdio.h>
  15229.  
  15230.  #include <os2.h>
  15231.  
  15232.  #include "IniEdit.h"
  15233.  
  15234.  
  15235.  /******************************* Constants *********************************/
  15236.  
  15237.  #define BUF_SIZE 132
  15238.  
  15239.  
  15240.  /******************************** Globals **********************************/
  15241.  
  15242.  static CHAR   szSearch[BUF_SIZE] = { 0 };           // Current search string
  15243.  static USHORT usLastIndex = 0;                      // Last Searched Item
  15244.  
  15245.  /******************************* Externals *********************************/
  15246.  
  15247.  extern USHORT        cAppNames;                     // see iniedit.c
  15248.  extern HWND          hwndList;
  15249.  extern PGROUPSTRUCT  pGroups;
  15250.  extern HAB           habIniEdit;
  15251.  extern HWND          FocusWindow;
  15252.  
  15253.  
  15254.  /****************************** Function Header ****************************\
  15255.  *
  15256.  * SearchWndProc
  15257.  *
  15258.  *
  15259.  * Handles the Search Dialog Box messages
  15260.  *
  15261.  \***************************************************************************/
  15262.  
  15263.  MRESULT _loadds EXPENTRY SearchWndProc(HWND hwndDialog, USHORT msg,
  15264.          MPARAM mp1, MPARAM mp2)
  15265.  {
  15266.      HWND   hwndText;                            // Current Text Window
  15267.  
  15268.  
  15269.      switch (msg)
  15270.          {
  15271.  
  15272.          case WM_INITDLG:
  15273.              hwndText = WinWindowFromID( hwndDialog, IDDI_SEARCH_TEXT );
  15274.              WinSetWindowText(hwndText, szSearch);
  15275.              WinSendMsg( hwndText, EM_SETSEL,
  15276.                      MPFROM2SHORT(0, strlen(szSearch)), (MPARAM)0 );
  15277.  
  15278.              break;
  15279.  
  15280.          case WM_COMMAND:
  15281.              switch( LOUSHORT( mp1 ) )
  15282.                  {
  15283.  
  15284.                  case IDDI_SEARCH_OK:
  15285.                      hwndText = WinWindowFromID( hwndDialog, IDDI_SEARCH_TEXT
  15286.                      WinQueryWindowText( hwndText, BUF_SIZE, szSearch );
  15287.                      WinDismissDlg( hwndDialog, 0 );
  15288.  
  15289.                      if( (usLastIndex = SHORT1FROMMR(WinSendMsg( hwndList, LM_
  15290.                              MPFROM2SHORT( LSS_SUBSTRING, LIT_FIRST),
  15291.                              MPFROMP( szSearch )) ) != LIT_NONE ))
  15292.                          {
  15293.                          WinSendMsg( hwndList, LM_SELECTITEM,
  15294.                                  MPFROM2SHORT( (usLastIndex), NULL),
  15295.                                  MPFROM2SHORT( TRUE, NULL ) );
  15296.                          }
  15297.                      else  /* not found */
  15298.                          {
  15299.                          usLastIndex = LIT_FIRST;
  15300.                          WinAlarm( HWND_DESKTOP, 0);
  15301.                          }
  15302.                      break;
  15303.  
  15304.                  case IDDI_SEARCH_NEXT:
  15305.                      FindNext();
  15306.                      break;
  15307.  
  15308.                  default:
  15309.                      return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15310.                      break;
  15311.                  }
  15312.  
  15313.          default:
  15314.              return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15315.              break;
  15316.          }
  15317.  
  15318.      return 0L;
  15319.  
  15320.  }  /* SearchWndProc */
  15321.  
  15322.  
  15323.  /****************************** Function Header ****************************\
  15324.  *
  15325.  * FindNext
  15326.  *
  15327.  *
  15328.  * Finds the next instance of the current search string starting from the
  15329.  * Last searched position
  15330.  *
  15331.  \***************************************************************************/
  15332.  
  15333.  VOID FindNext()
  15334.  {
  15335.     if( (usLastIndex = SHORT1FROMMR(WinSendMsg( hwndList, LM_SEARCHSTRING,
  15336.             MPFROM2SHORT( LSS_SUBSTRING, usLastIndex),
  15337.             MPFROMP( szSearch )) ) != LIT_NONE ))
  15338.         {
  15339.         WinSendMsg( hwndList, LM_SELECTITEM,
  15340.                 MPFROM2SHORT( (usLastIndex), NULL),
  15341.                 MPFROM2SHORT( TRUE, NULL ) );
  15342.         }
  15343.     else   /* alarm if not found */
  15344.         WinAlarm( HWND_DESKTOP, 0);
  15345.  
  15346.  }  /* FindNext */
  15347.  
  15348.  
  15349.  /****************************** Function Header ****************************\
  15350.  *
  15351.  * AddKeyWndProc
  15352.  *
  15353.  *
  15354.  * Handles the AddKey Dialog Box messages
  15355.  * Will facilitate adding new keys for a given App Name
  15356.  *
  15357.  \***************************************************************************/
  15358.  
  15359.  MRESULT _loadds EXPENTRY AddKeyWndProc(HWND hwndDialog, USHORT msg,
  15360.          MPARAM mp1, MPARAM mp2)
  15361.  {
  15362.      HWND   hwndTextApp;                         // Handle for App Text Window
  15363.      HWND   hwndTextKey;
  15364.      HWND   hwndTextValue;
  15365.      CHAR   szApp[BUF_SIZE];                     // String Contents
  15366.      CHAR   szKey[BUF_SIZE];
  15367.      CHAR   szValue[BUF_SIZE];
  15368.  
  15369.  
  15370.      switch (msg)
  15371.          {
  15372.          case WM_INITDLG:
  15373.              WinSendDlgItemMsg(hwndDialog, IDDI_ADD_KEY_TEXT_APP, EM_SETTEXTLI
  15374.                      MPFROMSHORT(MAX_STRING_LEN), 0L);
  15375.              WinSendDlgItemMsg(hwndDialog, IDDI_ADD_KEY_TEXT_KEY, EM_SETTEXTLI
  15376.                      MPFROMSHORT(MAX_STRING_LEN), 0L);
  15377.              WinSendDlgItemMsg(hwndDialog, IDDI_ADD_KEY_TEXT_VAL, EM_SETTEXTLI
  15378.                      MPFROMSHORT(MAX_STRING_LEN), 0L);
  15379.              break;
  15380.          case WM_COMMAND:
  15381.              switch( LOUSHORT( mp1 ) )
  15382.                  {
  15383.  
  15384.                  case IDDI_ADD_KEY_OK:
  15385.                      hwndTextApp = WinWindowFromID( hwndDialog, IDDI_ADD_KEY_T
  15386.                      WinQueryWindowText( hwndTextApp, BUF_SIZE, szApp );
  15387.  
  15388.                      hwndTextKey = WinWindowFromID( hwndDialog, IDDI_ADD_KEY_T
  15389.                      WinQueryWindowText( hwndTextKey, BUF_SIZE, szKey );
  15390.  
  15391.                      hwndTextValue = WinWindowFromID( hwndDialog, IDDI_ADD_KEY
  15392.                      WinQueryWindowText( hwndTextValue, BUF_SIZE, szValue );
  15393.  
  15394.                      WinDismissDlg( hwndDialog, 0 );
  15395.  
  15396.                      /* if the App is NULL forget it */
  15397.                      if( *szApp == (CHAR)0 )
  15398.                          {
  15399.                          break;
  15400.                          }
  15401.  
  15402.                      /* if the Key is NULL forget it */
  15403.                      if( *szKey == (CHAR)0 )
  15404.                          {
  15405.                          break;
  15406.                          }
  15407.  
  15408.                      /* if the Value is NULL forget it */
  15409.                      if( *szValue == (CHAR)0 )
  15410.                          {
  15411.                          break;
  15412.                          }
  15413.  
  15414.                      if( !WinWriteProfileString( habIniEdit, szApp, szKey, szV
  15415.                          ;
  15416.                      break;
  15417.  
  15418.                  default:
  15419.                      return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15420.                      break;
  15421.                  }
  15422.  
  15423.          default:
  15424.              return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15425.              break;
  15426.          }
  15427.  
  15428.      return 0L;
  15429.  
  15430.  }  /* AddKeyWndProc */
  15431.  
  15432.  
  15433.  /****************************** Function Header ****************************\
  15434.  *
  15435.  * ChangeKeyWndProc
  15436.  *
  15437.  *
  15438.  * Handles the ChangeKey Dialog Box messages
  15439.  * Will facilitate changing a key's value given an app, key and new value
  15440.  *
  15441.  \***************************************************************************/
  15442.  
  15443.  MRESULT _loadds EXPENTRY ChangeKeyWndProc(HWND hwndDialog, USHORT msg,
  15444.          MPARAM mp1, MPARAM mp2)
  15445.  {
  15446.      HWND     hwndTextApp;                       // Handle for App Text Window
  15447.      HWND     hwndTextKey;
  15448.      HWND     hwndTextVal;
  15449.      CHAR     szApp[BUF_SIZE];                   // String Contents
  15450.      CHAR     szKey[BUF_SIZE];
  15451.      CHAR     szVal[BUF_SIZE];
  15452.  
  15453.  
  15454.      switch (msg)
  15455.          {
  15456.          case WM_INITDLG:
  15457.              if( FocusWindow )
  15458.                  {
  15459.  
  15460.                  FocusWindow = WinWindowFromID( hwndDialog, IDDI_CHANGE_KEY_TE
  15461.                  WinSetFocus( HWND_DESKTOP, FocusWindow);
  15462.                  WinQueryWindowText( FocusWindow, BUF_SIZE, szVal );
  15463.  
  15464.                  FocusWindow = (HWND)NULL;
  15465.  
  15466.                  return((MRESULT) TRUE );
  15467.                  } else {
  15468.                  WinSendDlgItemMsg(hwndDialog, IDDI_CHANGE_KEY_TEXT_APP, EM_SE
  15469.                          MPFROMSHORT(MAX_STRING_LEN), 0L);
  15470.                  WinSendDlgItemMsg(hwndDialog, IDDI_CHANGE_KEY_TEXT_KEY, EM_SE
  15471.                          MPFROMSHORT(MAX_STRING_LEN), 0L);
  15472.                  WinSendDlgItemMsg(hwndDialog, IDDI_CHANGE_KEY_TEXT_VAL, EM_SE
  15473.                          MPFROMSHORT(MAX_STRING_LEN), 0L);
  15474.                  }
  15475.              break;
  15476.  
  15477.          case WM_COMMAND:
  15478.              switch( LOUSHORT( mp1 ) )
  15479.                  {
  15480.  
  15481.                  case IDDI_CHANGE_KEY_OK:
  15482.                      hwndTextApp = WinWindowFromID( hwndDialog, IDDI_CHANGE_KE
  15483.                      WinQueryWindowText( hwndTextApp, BUF_SIZE, szApp );
  15484.  
  15485.                      hwndTextKey = WinWindowFromID( hwndDialog, IDDI_CHANGE_KE
  15486.                      WinQueryWindowText( hwndTextKey, BUF_SIZE, szKey );
  15487.  
  15488.                      hwndTextVal = WinWindowFromID( hwndDialog, IDDI_CHANGE_KE
  15489.                      WinQueryWindowText( hwndTextVal, BUF_SIZE, szVal );
  15490.  
  15491.  
  15492.                      WinDismissDlg( hwndDialog, IDDI_CHANGE_KEY_OK );
  15493.  
  15494.                      /* if the App is NULL forget it */
  15495.                      if( *szApp == (CHAR)0 )
  15496.                          {
  15497.                          break;
  15498.                          }
  15499.  
  15500.                      /* if the Key is NULL forget it */
  15501.                      if( *szKey == (CHAR)0 )
  15502.                          {
  15503.                          break;
  15504.                          }
  15505.  
  15506.                      /* if the Value is NULL forget it */
  15507.                      if( *szVal == (CHAR)0 )
  15508.                          {
  15509.                          break;
  15510.                          }
  15511.  
  15512.  
  15513.                      if( !WinWriteProfileString( habIniEdit, szApp, szKey, szV
  15514.  
  15515.                      break;
  15516.  
  15517.                  default:
  15518.                      return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15519.                      break;
  15520.                  }
  15521.  
  15522.          default:
  15523.              return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15524.              break;
  15525.          }
  15526.  
  15527.      return 0L;
  15528.  
  15529.  }  /* ChangeKeyWndProc */
  15530.  
  15531.  
  15532.  /****************************** Function Header ****************************\
  15533.  *
  15534.  * DelKeyWndProc
  15535.  *
  15536.  *
  15537.  * Handles the DelKey Dialog Box messages
  15538.  * Will facilitate deleting a key value given an app and the key
  15539.  *
  15540.  \***************************************************************************/
  15541.  
  15542.  MRESULT _loadds EXPENTRY DelKeyWndProc(HWND hwndDialog, USHORT msg,
  15543.          MPARAM mp1, MPARAM mp2)
  15544.  {
  15545.      HWND   hwndTextApp;                         // Handle for App Text Window
  15546.      HWND   hwndTextKey;
  15547.      CHAR   szApp[BUF_SIZE];                     // String Contents
  15548.      CHAR   szKey[BUF_SIZE];
  15549.  
  15550.  
  15551.      switch (msg)
  15552.          {
  15553.          case WM_INITDLG:
  15554.              WinSendDlgItemMsg(hwndDialog, IDDI_DEL_KEY_TEXT_APP, EM_SETTEXTLI
  15555.                      MPFROMSHORT(MAX_STRING_LEN), 0L);
  15556.              WinSendDlgItemMsg(hwndDialog, IDDI_DEL_KEY_TEXT_KEY, EM_SETTEXTLI
  15557.                      MPFROMSHORT(MAX_STRING_LEN), 0L);
  15558.              break;
  15559.          case WM_COMMAND:
  15560.              switch( LOUSHORT( mp1 ) )
  15561.                  {
  15562.  
  15563.                  case IDDI_DEL_KEY_OK:
  15564.                      hwndTextApp = WinWindowFromID( hwndDialog, IDDI_DEL_KEY_T
  15565.                      WinQueryWindowText( hwndTextApp, BUF_SIZE, szApp );
  15566.  
  15567.                      hwndTextKey = WinWindowFromID( hwndDialog, IDDI_DEL_KEY_T
  15568.                      WinQueryWindowText( hwndTextKey, BUF_SIZE, szKey );
  15569.  
  15570.  
  15571.                      WinDismissDlg( hwndDialog, 0 );
  15572.  
  15573.                      /* if the App is NULL forget it */
  15574.                      if( *szApp == (CHAR)0 )
  15575.                          {
  15576.                          break;
  15577.                          }
  15578.  
  15579.                      /* if the Key is NULL forget it */
  15580.                      if( *szKey == (CHAR)0 )
  15581.                          {
  15582.                          break;
  15583.                          }
  15584.  
  15585.  
  15586.                      if( !WinWriteProfileString( habIniEdit, szApp, szKey, (PC
  15587.                          ;
  15588.                      break;
  15589.  
  15590.                  default:
  15591.                      return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15592.                      break;
  15593.                  }
  15594.  
  15595.          default:
  15596.              return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15597.              break;
  15598.          }
  15599.  
  15600.      return 0L;
  15601.  
  15602.  }  /* DelKeyProc */
  15603.  
  15604.  
  15605.  /****************************** Function Header ****************************\
  15606.  *
  15607.  * DelAppWndProc
  15608.  *
  15609.  *
  15610.  * Handles the DelApp Dialog Box messages
  15611.  * Will facilitate deleting all keys from a given app name
  15612.  *
  15613.  \***************************************************************************/
  15614.  
  15615.  MRESULT _loadds EXPENTRY DelAppWndProc(HWND hwndDialog, USHORT msg,
  15616.          MPARAM mp1, MPARAM mp2)
  15617.  {
  15618.      HWND   hwndTextApp;                         // App Name Window
  15619.      CHAR   szApp[BUF_SIZE];                     // String Contents of Window
  15620.  
  15621.  
  15622.      switch (msg)
  15623.          {
  15624.          case WM_INITDLG:
  15625.              WinSendDlgItemMsg(hwndDialog, IDDI_DEL_APP_TEXT_APP, EM_SETTEXTLI
  15626.                      MPFROMSHORT(MAX_STRING_LEN), 0L);
  15627.              break;
  15628.  
  15629.          case WM_COMMAND:
  15630.              switch( LOUSHORT( mp1 ) )
  15631.                  {
  15632.  
  15633.                  case IDDI_DEL_APP_OK:
  15634.                      hwndTextApp = WinWindowFromID( hwndDialog, IDDI_DEL_APP_T
  15635.                      WinQueryWindowText( hwndTextApp, BUF_SIZE, szApp );
  15636.  
  15637.                      WinDismissDlg( hwndDialog, 0 );
  15638.  
  15639.                      /* if the App is NULL forget it */
  15640.                      if( *szApp == (CHAR)0 )
  15641.                          {
  15642.                          break;
  15643.                          }
  15644.  
  15645.                      if( !WinWriteProfileString( habIniEdit, szApp, (PCHAR)NUL
  15646.                          ;
  15647.  
  15648.                      break;
  15649.  
  15650.                  default:
  15651.                      return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15652.                      break;
  15653.                  }
  15654.  
  15655.          default:
  15656.              return WinDefDlgProc(hwndDialog, msg, mp1, mp2);
  15657.              break;
  15658.          }
  15659.  
  15660.      return 0L;
  15661.  
  15662.  }  /* DelAppWndProc */
  15663.  
  15664.  
  15665.  DLGSAMP.C
  15666.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DLGSAMP\DLGSAMP.C
  15667.  
  15668.  /*
  15669.      DLGSAMP -- Dialog Box Sample Application
  15670.      Created by Microsoft Corporation, 1989
  15671.  */
  15672.  
  15673.  #define INCL_WINBUTTONS
  15674.  #define INCL_WINDIALOGS
  15675.  #define INCL_WINERRORS
  15676.  #define INCL_WINFRAMEMGR
  15677.  #define INCL_WININPUT
  15678.  #define INCL_WINLISTBOXES
  15679.  #define INCL_WINMENUS
  15680.  #define INCL_WINMESSAGEMGR
  15681.  #define INCL_WINRECTANGLES
  15682.  #define INCL_WINSWITCHLIST
  15683.  #define INCL_WINSYS
  15684.  #define INCL_WINWINDOWMGR
  15685.  #define M_I86L
  15686.  #include <os2.h>
  15687.  
  15688.  #include <string.h>
  15689.  #include <stdlib.h>
  15690.  
  15691.  #include "dlgsamp.h"
  15692.  #include "dlgsamp1.h"
  15693.  
  15694.  /*
  15695.      Function Prototypes
  15696.  */
  15697.  
  15698.  VOID NEAR cdecl main(VOID);
  15699.  
  15700.  /* Local Routines */
  15701.  VOID cdecl CenterDlgBox(HWND);
  15702.  VOID cdecl CheckColor(HWND, SHORT, COLOR *);
  15703.  VOID cdecl EnableModality(HWND, BOOL);
  15704.  BOOL cdecl IsIntInRange(HWND, SHORT, SHORT, SHORT, SHORT, SHORT);
  15705.  VOID cdecl LoadDialog(HWND, HWND, SHORT, PFNWP, BOOL);
  15706.  VOID cdecl MainWndCommand(HWND, USHORT, BOOL *);
  15707.  VOID cdecl MainWndPaint(HWND);
  15708.  VOID cdecl SetModality(HWND, BOOL);
  15709.  VOID cdecl Trace(PSZ, PSZ);
  15710.  
  15711.  /* Window Procedures */
  15712.  MRESULT EXPENTRY fnwpMainWnd(HWND, USHORT, MPARAM, MPARAM);
  15713.  MRESULT EXPENTRY fnwpEntryFieldDlg(HWND, USHORT, MPARAM, MPARAM);
  15714.  MRESULT EXPENTRY fnwpAutoRadioButtonDlg(HWND, USHORT, MPARAM, MPARAM);
  15715.  MRESULT EXPENTRY fnwpCheckBoxDlg(HWND, USHORT, MPARAM, MPARAM);
  15716.  MRESULT EXPENTRY fnwpListBoxDlg(HWND, USHORT, MPARAM, MPARAM);
  15717.  MRESULT EXPENTRY fnwpAboutBoxDlg(HWND, USHORT, MPARAM, MPARAM);
  15718.  
  15719.  /*
  15720.      Global variables
  15721.  */
  15722.  COLOR colorClient = CLR_RED | CLR_BLUE;    /* Color of client area    */
  15723.  
  15724.  CHAR  szEntryField1[10] = "";              /* Used to pass back info  */
  15725.  CHAR  szEntryField2[10] = "";              /* from entry fields       */
  15726.                                             /* in EntryFieldDlg        */
  15727.  
  15728.  BOOL  bModality = TRUE;                    /* Does the user want modal*/
  15729.                                             /* or modeless dialogs?    */
  15730.  COLOR colorSave;
  15731.  CHAR  szSelection[LEN_LISTBOXENTRY] = "";  /* Used to pass back       */
  15732.                                             /* list box item selected  */
  15733.                                             /* in ListBoxDlg           */
  15734.  
  15735.  HAB   hab;                                 /* Anchor block handle     */
  15736.  HWND  hwndClient;                          /* Client Window handle    */
  15737.  HWND  hwndFrame;                           /* Frame Window handle     */
  15738.  HWND  hwndModelessDlg;                     /* Modeless Dialog handle  */
  15739.  
  15740.  /**************************************************************************
  15741.  *
  15742.  *   FUNCTION: main
  15743.  *
  15744.  *   Typical PM main function which initializes PM, creates a message queue,
  15745.  *   registers a window class, creates a window, gets and dispatches
  15746.  *   messages to its winproc until its time to quit, and then tidies up
  15747.  *   before terminating.
  15748.  *
  15749.  **************************************************************************/
  15750.  
  15751.  VOID NEAR cdecl main(  )
  15752.  {
  15753.    HMQ     hmq;                        /* Message Queue handle         */
  15754.    QMSG    qmsg;                       /* Message                      */
  15755.    ULONG   flCreate;
  15756.  
  15757.    hab   = WinInitialize( 0 );         /* Initialize PM                */
  15758.    hmq   = WinCreateMsgQueue( hab, 0 );/* Create application msg queue */
  15759.  
  15760.    WinRegisterClass(                   /* Register Window Class        */
  15761.        hab,                            /* Anchor block handle          */
  15762.        "DlgSamp Class",                /* Window Class name            */
  15763.        fnwpMainWnd,                    /* Address of Window Procedure  */
  15764.        (ULONG) NULL,                   /* No special class style       */
  15765.        0                               /* No extra window words        */
  15766.        );
  15767.  
  15768.    flCreate = FCF_STANDARD & ~FCF_ACCELTABLE;
  15769.  
  15770.    hwndFrame = WinCreateStdWindow(
  15771.          HWND_DESKTOP,                   /* Desktop Window is parent     */
  15772.          WS_VISIBLE,                     /* Window styles                */
  15773.          (PVOID)&flCreate,               /* Window creation parameters   */
  15774.          "DlgSamp Class",                /* Window Class name            */
  15775.          "",                             /* Window Text                  */
  15776.          0L,                             /* Client style                 */
  15777.          (HMODULE) NULL,                 /* Module handle                */
  15778.          ID_MAINWND,                     /* Window ID                    */
  15779.          (HWND FAR *)&hwndClient         /* Client Window handle         */
  15780.          );
  15781.  
  15782.  
  15783.    /* Message Loop */
  15784.    while( WinGetMsg( hab, (PQMSG)&qmsg, (HWND)NULL, 0, 0 ) )
  15785.      WinDispatchMsg( hab, (PQMSG)&qmsg );
  15786.  
  15787.    /* Cleanup code */
  15788.    WinDestroyWindow( hwndFrame );
  15789.    WinDestroyMsgQueue( hmq );
  15790.    WinTerminate( hab );
  15791.  }
  15792.  
  15793.  /***********************************************************************
  15794.  *
  15795.  *   WinProc: fnwpMainWnd
  15796.  *
  15797.  *   Controls the state of the menu, and loads various dialogs.  The
  15798.  *   dialogs will be modal or modeless depending on the setting of the
  15799.  *   Modality menuitem.
  15800.  *
  15801.  ***********************************************************************/
  15802.  
  15803.  MRESULT  EXPENTRY fnwpMainWnd( hwnd, message, mp1, mp2 )
  15804.  HWND    hwnd;
  15805.  USHORT  message;
  15806.  MPARAM  mp1;
  15807.  MPARAM  mp2;
  15808.  {
  15809.    USHORT   Command;   /* Command passed by WM_COMMAND */
  15810.    SHORT    id;        /* ID of item selected from the list box */
  15811.  
  15812.    switch(message)
  15813.    {
  15814.      case WM_PAINT:
  15815.        MainWndPaint( hwnd );  /* Invoke window painting routine */
  15816.        break;
  15817.      case WM_HELP:
  15818.  /*********************************************************************
  15819.  *
  15820.  *   This will be received when either:-
  15821.  *
  15822.  *   1. The user hits the F1 key
  15823.  *   2. The user clicks on the action bar item F1=Help
  15824.  *
  15825.  *********************************************************************/
  15826.        WinMessageBox( HWND_DESKTOP,
  15827.                       hwndFrame,
  15828.                       (PSZ)"Dialog Sample Application: Help",
  15829.                       (PSZ)"Try out the pulldown menus, or Alt+selection",
  15830.                       ID_MB,
  15831.                       MB_OK );
  15832.        break;
  15833.      case WM_COMMAND:
  15834.        Command = SHORT1FROMMP( mp1 );
  15835.        MainWndCommand( hwnd, Command, &bModality );
  15836.        break;
  15837.      case DLGSAMP_EFCOMPLETE:
  15838.        WinQueryWindowText( WinWindowFromID( hwndModelessDlg, EF_1 ),
  15839.                            sizeof( szEntryField1 ), szEntryField1 );
  15840.        WinQueryWindowText( WinWindowFromID( hwndModelessDlg, EF_2 ),
  15841.                            sizeof( szEntryField2 ), szEntryField2 );
  15842.        WinInvalidateRect( hwnd, NULL, FALSE );/* Request whole window repaint
  15843.        break;
  15844.      case DLGSAMP_LBCOMPLETE:
  15845.        id = SHORT1FROMMR( WinSendDlgItemMsg( hwndModelessDlg,
  15846.                                              LB_1,
  15847.                                              LM_QUERYSELECTION,
  15848.                                              0L,
  15849.                                              0L ) );
  15850.        if( id == LIT_NONE )
  15851.          strcpy( szSelection, "" );
  15852.        else
  15853.          WinSendDlgItemMsg( hwndModelessDlg,
  15854.                             LB_1,
  15855.                             LM_QUERYITEMTEXT,
  15856.                             MPFROM2SHORT( id, sizeof( szSelection ) ),
  15857.                             MPFROMP( szSelection ) );
  15858.        break;
  15859.      case DLGSAMP_RBCOMPLETE:
  15860.      case DLGSAMP_CBCOMPLETE:
  15861.        break;
  15862.      case DLGSAMP_DESTROYDLG:
  15863.        WinDestroyWindow( hwndModelessDlg );
  15864.        EnableModality( hwndFrame, TRUE );
  15865.        WinInvalidateRect( hwnd, NULL, FALSE );/* Request whole window repaint
  15866.        break;
  15867.      case WM_CLOSE:
  15868.        WinPostMsg( hwnd, WM_QUIT, 0L, 0L );  /* Cause termination    */
  15869.        break;
  15870.      default:
  15871.        return WinDefWindowProc( hwnd, message, mp1, mp2 );
  15872.    }
  15873.    return FALSE;
  15874.  }
  15875.  
  15876.  /***********************************************************************
  15877.  *
  15878.  *  DlgProc:  fnwpEntryFieldDlg
  15879.  *
  15880.  *  A dialog proc which captures and validates the contents of two
  15881.  *  entry fields.
  15882.  *
  15883.  ***********************************************************************/
  15884.  
  15885.  MRESULT EXPENTRY fnwpEntryFieldDlg( hwndDlg, message, mp1, mp2 )
  15886.  HWND    hwndDlg;
  15887.  USHORT  message;
  15888.  MPARAM  mp1;
  15889.  MPARAM  mp2;
  15890.  {
  15891.    switch (message)
  15892.    {
  15893.      case WM_INITDLG:
  15894.        CenterDlgBox( hwndDlg );
  15895.        break;
  15896.      case WM_COMMAND:
  15897.        switch( SHORT1FROMMP( mp1 ) )
  15898.        {
  15899.          case DID_OK: /* Enter key or pushbutton pressed/ selected */
  15900.  
  15901.  /***************************************************************************
  15902.  *
  15903.  *   Validate the contents of the two entry fields
  15904.  *
  15905.  ***************************************************************************/
  15906.  
  15907.            if( !IsIntInRange( hwndDlg, EF_1, 1, 100, ERR_EFINVALID, ID_MB ) )
  15908.              return FALSE;
  15909.            if( !IsIntInRange( hwndDlg, EF_2, 1, 100, ERR_EFINVALID, ID_MB ) )
  15910.              return FALSE;
  15911.  
  15912.  /***************************************************************************
  15913.  *
  15914.  *   A modal dialog is destroyed before control is returned to the
  15915.  *   invoking winproc, so it must pass the contents of its Entry Fields etc.
  15916.  *   back to the invoking window before it returns.
  15917.  *
  15918.  *   When a modeless dialog box returns it still continues to exist. It
  15919.  *   could pass the contents of its Entry Fields etc. back to the
  15920.  *   invoking window in several ways.
  15921.  *
  15922.  *   Here a user message is posted to the invoking window to say that the
  15923.  *   dialog has completed. The invoking window then has an opportunity
  15924.  *   to extract the contents of the Entry Fields etc.
  15925.  *
  15926.  ***************************************************************************/
  15927.  
  15928.            if( bModality )
  15929.            {
  15930.              WinQueryWindowText( WinWindowFromID( hwndDlg, EF_1 ),
  15931.                                  sizeof( szEntryField1),
  15932.                                  szEntryField1 );
  15933.              WinQueryWindowText( WinWindowFromID( hwndDlg, EF_2 ),
  15934.                                  sizeof( szEntryField2),
  15935.                                  szEntryField2 );
  15936.            }
  15937.            else
  15938.              WinPostMsg( hwndClient, DLGSAMP_EFCOMPLETE, 0L, 0L );
  15939.  
  15940.          case DID_CANCEL:/* Escape key or CANCEL pushbutton pressed/selected *
  15941.            if( bModality )
  15942.              WinDismissDlg( hwndDlg,TRUE );
  15943.            else
  15944.              WinPostMsg( hwndClient, DLGSAMP_DESTROYDLG, 0L, 0L );
  15945.            return FALSE;
  15946.          default:
  15947.            break;
  15948.        }
  15949.        break;
  15950.  
  15951.      default:  /* Pass all other messages to the default dialog proc */
  15952.        return WinDefDlgProc( hwndDlg, message, mp1, mp2 );
  15953.    }
  15954.    return FALSE;
  15955.  }
  15956.  
  15957.  /***********************************************************************
  15958.  *
  15959.  *  DlgProc:  fnwpAutoRadioButtonDlg
  15960.  *
  15961.  *  A dialog procedure which uses auto radio buttons to change the
  15962.  *  color of the Client Area window.
  15963.  *
  15964.  ***********************************************************************/
  15965.  
  15966.  MRESULT EXPENTRY fnwpAutoRadioButtonDlg( hwndDlg, message, mp1, mp2 )
  15967.  HWND    hwndDlg;
  15968.  USHORT  message;
  15969.  MPARAM  mp1;
  15970.  MPARAM  mp2;
  15971.  {
  15972.    switch (message)
  15973.    {
  15974.      case WM_INITDLG:
  15975.        colorSave = colorClient;
  15976.        CenterDlgBox( hwndDlg );
  15977.        if ( colorClient == CLR_RED )
  15978.          WinPostMsg( WinWindowFromID( hwndDlg, RB_RED ),
  15979.                      BM_SETCHECK,
  15980.                      MPFROM2SHORT( TRUE, 0 ),
  15981.                      0L );
  15982.  
  15983.        if ( colorClient == CLR_GREEN )
  15984.          WinPostMsg( WinWindowFromID( hwndDlg, RB_GREEN ),
  15985.                      BM_SETCHECK,
  15986.                      MPFROM2SHORT( TRUE, 0 ),
  15987.                      0L );
  15988.  
  15989.        if ( colorClient == CLR_BLUE )
  15990.          WinPostMsg( WinWindowFromID( hwndDlg, RB_BLUE ),
  15991.                      BM_SETCHECK,
  15992.                      MPFROM2SHORT( TRUE, 0 ),
  15993.                      0L );
  15994.  
  15995.        break;
  15996.      case WM_CONTROL:
  15997.        if( SHORT2FROMMP( mp1 ) == BN_CLICKED )
  15998.          switch( SHORT1FROMMP( mp1 ) )
  15999.          {
  16000.            case RB_RED:
  16001.              colorClient = CLR_RED;
  16002.              break;
  16003.            case RB_GREEN:
  16004.              colorClient = CLR_GREEN;
  16005.              break;
  16006.            case RB_BLUE:
  16007.              colorClient = CLR_BLUE;
  16008.              break;
  16009.            default:
  16010.             return FALSE;
  16011.          }
  16012.          WinInvalidateRect( hwndClient, NULL, FALSE );
  16013.          break;
  16014.      case WM_COMMAND:
  16015.        switch( SHORT1FROMMP( mp1 ) )
  16016.        {
  16017.          case DID_OK:     /* Enter key or pushbutton pressed/ selected
  16018.            if( !bModality )
  16019.              WinPostMsg( hwndClient, DLGSAMP_RBCOMPLETE, 0L, 0L );
  16020.            break;
  16021.          case DID_CANCEL: /* Escape key or CANCEL pushbutton pressed/selected
  16022.            colorClient = colorSave;
  16023.            break;
  16024.          default:
  16025.            return WinDefDlgProc( hwndDlg, message, mp1, mp2 );
  16026.        }
  16027.        if( bModality )
  16028.          WinDismissDlg( hwndDlg, TRUE );
  16029.        else
  16030.          WinPostMsg( hwndClient, DLGSAMP_DESTROYDLG, 0L, 0L );
  16031.        break;
  16032.  
  16033.      default:  /* Pass all other messages to the default dialog proc */
  16034.        return WinDefDlgProc( hwndDlg, message, mp1, mp2 );
  16035.    }
  16036.    return FALSE;
  16037.  }
  16038.  
  16039.  
  16040.  /***********************************************************************
  16041.  *
  16042.  *  DlgProc:  fnwpCheckBoxDlg
  16043.  *
  16044.  *  A dialog procedure to which use checkboxes to change the color
  16045.  *  of the Client Area Window.
  16046.  *
  16047.  ***********************************************************************/
  16048.  
  16049.  MRESULT EXPENTRY fnwpCheckBoxDlg( hwndDlg, message, mp1, mp2 )
  16050.  HWND    hwndDlg;
  16051.  USHORT  message;
  16052.  MPARAM  mp1;
  16053.  MPARAM  mp2;
  16054.  {
  16055.    switch (message)
  16056.    {
  16057.      case WM_INITDLG:
  16058.        CenterDlgBox( hwndDlg );
  16059.        colorSave = colorClient;
  16060.        if( (colorClient & CLR_RED) == CLR_RED )
  16061.          WinPostMsg( WinWindowFromID( hwndDlg, CB_RED ),
  16062.                      BM_SETCHECK,
  16063.                      MPFROM2SHORT( TRUE,0 ),
  16064.                      0L );
  16065.        if( (colorClient & CLR_GREEN) == CLR_GREEN )
  16066.          WinPostMsg( WinWindowFromID( hwndDlg, CB_GREEN ),
  16067.                      BM_SETCHECK,
  16068.                      MPFROM2SHORT( TRUE,0 ),
  16069.                      0L );
  16070.        if( (colorClient & CLR_BLUE) == CLR_BLUE )
  16071.          WinPostMsg( WinWindowFromID( hwndDlg, CB_BLUE ),
  16072.                      BM_SETCHECK,
  16073.                      MPFROM2SHORT( TRUE,0 ),
  16074.                      0L );
  16075.        break;
  16076.      case WM_CONTROL:                  /* User has clicked on a checkbox */
  16077.        if( SHORT2FROMMP( mp1 ) == BN_CLICKED )
  16078.          CheckColor( hwndDlg, SHORT1FROMMP( mp1 ), &colorClient );
  16079.        WinInvalidateRect( hwndClient, NULL, FALSE );
  16080.        break;
  16081.      case WM_COMMAND:
  16082.        switch( SHORT1FROMMP( mp1 ) )
  16083.        {
  16084.          case DID_OK:     /* Enter key or pushbutton pressed/ selected */
  16085.            if( !bModality )
  16086.              WinPostMsg( hwndClient, DLGSAMP_CBCOMPLETE, 0L, 0L );
  16087.            break;
  16088.          case DID_CANCEL: /* Escape key or CANCEL pushbutton pressed/selected
  16089.            colorClient = colorSave;
  16090.            break;
  16091.          default:
  16092.            return WinDefDlgProc( hwndDlg, message, mp1, mp2 );
  16093.        }
  16094.        if( bModality )
  16095.          WinDismissDlg( hwndDlg, TRUE );
  16096.        else
  16097.          WinPostMsg( hwndClient, DLGSAMP_DESTROYDLG, 0L, 0L );
  16098.        return FALSE;
  16099.  
  16100.      default:  /* Pass all other messages to the default dialog proc */
  16101.        return WinDefDlgProc( hwndDlg, message, mp1, mp2 );
  16102.    }
  16103.    return FALSE;
  16104.  }
  16105.  
  16106.  /***********************************************************************
  16107.  *
  16108.  *  DlgProc:  fnwpListBoxDlg
  16109.  *
  16110.  ***********************************************************************/
  16111.  
  16112.  MRESULT EXPENTRY fnwpListBoxDlg( hwndDlg, message, mp1, mp2 )
  16113.  HWND    hwndDlg;
  16114.  USHORT  message;
  16115.  MPARAM  mp1;
  16116.  MPARAM  mp2;
  16117.  {
  16118.    CHAR szBuffer[LEN_LISTBOXENTRY];
  16119.    SHORT  i;
  16120.    SHORT  id;
  16121.  
  16122.    switch (message)
  16123.    {
  16124.      case WM_INITDLG:
  16125.        CenterDlgBox( hwndDlg );
  16126.  
  16127.  /*************************************************************************
  16128.  *
  16129.  *   Initialize the listbox with a set of strings loaded from a
  16130.  *   resource file.
  16131.  *
  16132.  *************************************************************************/
  16133.  
  16134.        for ( i = 0; i < NUM_LISTBOXENTRIES; i++ )
  16135.        {
  16136.          WinLoadString( hab,
  16137.                         (HMODULE) NULL,
  16138.                         LBI_1 + i,
  16139.                         LEN_LISTBOXENTRY,
  16140.                         (PSZ)szBuffer
  16141.                       );
  16142.          WinSendDlgItemMsg( hwndDlg,
  16143.                             LB_1,
  16144.                             LM_INSERTITEM,
  16145.                             MPFROM2SHORT( LIT_END, 0 ),
  16146.                             MPFROMP( szBuffer )
  16147.                           );
  16148.        }
  16149.        break;
  16150.      case WM_COMMAND:
  16151.        switch( SHORT1FROMMP( mp1 ) )
  16152.        {
  16153.          case DID_OK:     /* Enter key or pushbutton pressed/ selected */
  16154.            if( bModality )
  16155.            {
  16156.  
  16157.  /***********************************************************************
  16158.  *
  16159.  *   Find out which item (if any) was selected and return the selected
  16160.  *   item text.
  16161.  *
  16162.  ***********************************************************************/
  16163.  
  16164.              id = SHORT1FROMMR( WinSendDlgItemMsg( hwndDlg,
  16165.                                                    LB_1,
  16166.                                                    LM_QUERYSELECTION,
  16167.                                                    0L,
  16168.                                                    0L ) );
  16169.              if( id == LIT_NONE )
  16170.                strcpy( szSelection, "" );
  16171.              else
  16172.                WinSendDlgItemMsg( hwndDlg,
  16173.                                   LB_1,
  16174.                                   LM_QUERYITEMTEXT,
  16175.                                   MPFROM2SHORT( id, LEN_LISTBOXENTRY ),
  16176.                                   MPFROMP( szSelection ) );
  16177.            }
  16178.            else
  16179.              WinPostMsg( hwndClient, DLGSAMP_LBCOMPLETE, 0L, 0L );
  16180.          case DID_CANCEL: /* Escape key or CANCEL pushbutton pressed/selected
  16181.            if( bModality )
  16182.              WinDismissDlg( hwndDlg, TRUE );
  16183.            else
  16184.              WinPostMsg( hwndClient, DLGSAMP_DESTROYDLG, 0L, 0L );
  16185.            return FALSE;
  16186.          default:
  16187.            break;
  16188.        }
  16189.        break;
  16190.  
  16191.      default:  /* Pass all other messages to the default dialog proc */
  16192.        return WinDefDlgProc( hwndDlg, message, mp1, mp2 );
  16193.    }
  16194.    return FALSE;
  16195.  }
  16196.  
  16197.  /*************************************************************************
  16198.  *
  16199.  *   FUNCTION : CenterDlgBox
  16200.  *
  16201.  *   Positions the dialog box in the center of the screen
  16202.  *
  16203.  *************************************************************************/
  16204.  
  16205.  VOID cdecl CenterDlgBox( hwnd )
  16206.  HWND hwnd;
  16207.  {
  16208.    SHORT ix, iy;
  16209.    SHORT iwidth, idepth;
  16210.    SWP   swp;
  16211.  
  16212.    iwidth = (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  16213.    idepth = (SHORT)WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  16214.    WinQueryWindowPos( hwnd, (PSWP)&swp );
  16215.    ix = ( iwidth  - swp.cx ) / 2;
  16216.    iy = ( idepth  - swp.cy ) / 2;
  16217.    WinSetWindowPos( hwnd, HWND_TOP, ix, iy, 0, 0, SWP_MOVE );
  16218.  }
  16219.  
  16220.  /***************************************************************************
  16221.  *
  16222.  *  FUNCTION: CheckColor
  16223.  *
  16224.  *  Toggle the Checked/UnChecked state of a checkbox and add/remove
  16225.  *  the corresponding CLR color component of the Client Area Color.
  16226.  *
  16227.  ***************************************************************************/
  16228.  
  16229.  VOID cdecl CheckColor( hwndDlg, iDlgItem, colorClient )
  16230.  HWND   hwndDlg;
  16231.  SHORT  iDlgItem;
  16232.  COLOR *colorClient;
  16233.  {
  16234.    BOOL  bChecked;
  16235.    COLOR color;
  16236.  
  16237.    switch( iDlgItem )
  16238.    {
  16239.      case CB_RED:
  16240.        color = CLR_RED;
  16241.        break;
  16242.      case CB_GREEN:
  16243.        color = CLR_GREEN;
  16244.        break;
  16245.      case CB_BLUE:
  16246.        color = CLR_BLUE;
  16247.        break;
  16248.      default:
  16249.        return;
  16250.    }
  16251.  
  16252.    bChecked = SHORT1FROMMR( WinSendMsg( WinWindowFromID( hwndDlg , iDlgItem ),
  16253.                                         BM_QUERYCHECK,
  16254.                                         0L,
  16255.                                         0L ) );
  16256.    WinPostMsg( WinWindowFromID( hwndDlg, iDlgItem ),
  16257.                BM_SETCHECK,
  16258.                MPFROM2SHORT( !bChecked, 0 ),
  16259.                0L );
  16260.    if( bChecked )                   /* If color previously checked */
  16261.      *colorClient -= color;         /* subtract it ... else        */
  16262.    else
  16263.      *colorClient += color;         /* ... add it.                 */
  16264.  }
  16265.  
  16266.  /**************************************************************************
  16267.  *
  16268.  *   FUNCTION: EnableModality
  16269.  *
  16270.  *   Enable or disable the Modality menuitems depending on the value
  16271.  *   of modal. This is done to prevent the user from altering the
  16272.  *   modality setting while a modeless dialog is active.
  16273.  *
  16274.  **************************************************************************/
  16275.  
  16276.  VOID cdecl EnableModality( hwnd, bModal )
  16277.  HWND hwnd;
  16278.  BOOL bModal;
  16279.  {
  16280.    if( bModal )
  16281.    {
  16282.      WinPostMsg( WinWindowFromID( hwnd, FID_MENU ),
  16283.                  MM_SETITEMATTR,
  16284.                  MPFROM2SHORT( MI_MODAL, TRUE ),
  16285.                  MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED ) );
  16286.      WinPostMsg( WinWindowFromID( hwnd, FID_MENU ),
  16287.                  MM_SETITEMATTR,
  16288.                  MPFROM2SHORT( MI_MODELESS, TRUE ),
  16289.                  MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED ) );
  16290.    }
  16291.    else
  16292.    {
  16293.      WinPostMsg( WinWindowFromID( hwnd, FID_MENU ),
  16294.                  MM_SETITEMATTR,
  16295.                  MPFROM2SHORT( MI_MODAL, TRUE ),
  16296.                  MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ) );
  16297.      WinPostMsg( WinWindowFromID( hwnd, FID_MENU ),
  16298.                  MM_SETITEMATTR,
  16299.                  MPFROM2SHORT( MI_MODELESS, TRUE ),
  16300.                  MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED ) );
  16301.    }
  16302.  }
  16303.  
  16304.  /***************************************************************************
  16305.  *
  16306.  *  FUNCTION: IsIntInRange.
  16307.  *
  16308.  *  Checks whether the value of a dialog item is in an integer in
  16309.  *  a given range.
  16310.  *
  16311.  ***************************************************************************/
  16312.  
  16313.  BOOL cdecl IsIntInRange( hwndDlg,  idEntryField,
  16314.                           iLoRange, iHiRange,
  16315.                           idErrMsg, idMessageBox )
  16316.  HWND hwndDlg;
  16317.  SHORT  idEntryField;
  16318.  SHORT  iLoRange;
  16319.  SHORT  iHiRange;
  16320.  SHORT  idErrMsg;
  16321.  SHORT  idMessageBox;
  16322.  {
  16323.    SHORT ivalue;
  16324.    CHAR  szErrMsg[80];
  16325.  
  16326.  /****************************************************************************
  16327.  *
  16328.  *   Validate an entry field.
  16329.  *
  16330.  *   If validation fails leave the dialog visible, issue an error message
  16331.  *   using a messagebox, and when the user dismisses the messagebox,
  16332.  *   set the input focus to the entry field containing the error. Leave
  16333.  *   the contents of the entry field unchanged, and return FALSE.
  16334.  *
  16335.  *   If validation is successful return the value in ivalue and return
  16336.  *   TRUE.
  16337.  *
  16338.  ****************************************************************************/
  16339.  
  16340.    if( !WinQueryDlgItemShort( hwndDlg, idEntryField, &ivalue, TRUE ) ||
  16341.        ( ivalue < iLoRange ) ||
  16342.        ( ivalue > iHiRange ) )
  16343.    {
  16344.      WinLoadString( hab, (HMODULE) NULL, idErrMsg, sizeof( szErrMsg ), szErrMs
  16345.      WinMessageBox( HWND_DESKTOP,
  16346.                     hwndFrame,
  16347.                     (PSZ)szErrMsg,
  16348.                     NULL,
  16349.                     idMessageBox,
  16350.                     MB_OK );
  16351.      WinSetFocus( HWND_DESKTOP, WinWindowFromID( hwndDlg, idEntryField ) );
  16352.      return FALSE;
  16353.    }
  16354.    else
  16355.      return TRUE;
  16356.  }
  16357.  
  16358.  /***********************************************************************
  16359.  *
  16360.  *  FUNCTION: LoadDialog
  16361.  *
  16362.  *  Use the appropriate functions to put up a modal or modeless
  16363.  *  dialog box depending on the setting of the bModality parameter.
  16364.  *
  16365.  ***********************************************************************/
  16366.  
  16367.  VOID cdecl LoadDialog( hwndParent, hwndOwner, idDlg, fnwpDlgProc, bModality )
  16368.  HWND  hwndParent;
  16369.  HWND  hwndOwner;
  16370.  SHORT idDlg;
  16371.  PFNWP fnwpDlgProc;
  16372.  BOOL  bModality;
  16373.  {
  16374.    EnableModality( hwndOwner, FALSE ); /* Disable the Modality menu item */
  16375.  
  16376.    if( bModality )
  16377.    {
  16378.      WinDlgBox( hwndParent,        /* Parent                    */
  16379.                 hwndOwner,         /* Owner                     */
  16380.                 fnwpDlgProc,       /* Address of dialog proc    */
  16381.                 (HMODULE) NULL,              /* Module handle             */
  16382.                 idDlg,             /* Id of dialog in resource  */
  16383.                 NULL );            /* Initialisation data       */
  16384.      EnableModality( hwndOwner, TRUE ); /* Enable the Modality menu item */
  16385.    }
  16386.    else
  16387.    {
  16388.      /*******************************************************************
  16389.      *
  16390.      *   Check to see if a modeless dialog is already running: if
  16391.      *   so destroy it before for loading the requested dialog. Save
  16392.      *   the handle of the new dialog in a global variable so that in
  16393.      *   can be accessed by the WinProc that issued LoadDialog.
  16394.      *
  16395.      *******************************************************************/
  16396.  
  16397.      if( WinIsWindow( hab, hwndModelessDlg ) )
  16398.        WinDestroyWindow( hwndModelessDlg );
  16399.      hwndModelessDlg = WinLoadDlg( hwndParent,
  16400.                                    hwndOwner,
  16401.                                    fnwpDlgProc,
  16402.                                    (HMODULE) NULL,
  16403.                                    idDlg,
  16404.                                    NULL );
  16405.    }
  16406.  }
  16407.  
  16408.  /*************************************************************************
  16409.  *
  16410.  *   FUNCTION: MainWndCommand
  16411.  *
  16412.  *   Take the appropriate action when a WM_COMMAND message is received by
  16413.  *   MainWndProc.  Issues calls which load dialogs in the prevailing state
  16414.  *   of modality.
  16415.  *
  16416.  *************************************************************************/
  16417.  
  16418.  VOID cdecl MainWndCommand( hwnd, Command, bModality )
  16419.  HWND   hwnd;
  16420.  USHORT Command;
  16421.  BOOL   *bModality;
  16422.  {
  16423.    USHORT idDlg;
  16424.    PFNWP  pfnDlgProc;
  16425.  
  16426.    switch( Command )
  16427.    {
  16428.      case MI_MODAL:
  16429.      case MI_MODELESS:
  16430.        *bModality = ( Command == MI_MODAL ) ? TRUE
  16431.                                             : FALSE;
  16432.        SetModality( WinQueryWindow( hwnd, QW_PARENT, FALSE ), *bModality );
  16433.        WinInvalidateRect( hwnd, NULL, FALSE );
  16434.        return;
  16435.      case MI_ENTRYFIELDEXAMPLE:
  16436.        idDlg      = DLG_ENTRYFIELDEXAMPLE;
  16437.        pfnDlgProc = (PFNWP)fnwpEntryFieldDlg;
  16438.        break;
  16439.      case MI_AUTORADIOBUTTONEXAMPLE:
  16440.        idDlg      = DLG_AUTORADIOBUTTONEXAMPLE;
  16441.        pfnDlgProc = (PFNWP)fnwpAutoRadioButtonDlg;
  16442.        break;
  16443.      case MI_CHECKBOXEXAMPLE:
  16444.        idDlg      = DLG_CHECKBOXEXAMPLE;
  16445.        pfnDlgProc = (PFNWP)fnwpCheckBoxDlg;
  16446.        break;
  16447.      case MI_LISTBOXEXAMPLE:
  16448.        idDlg      = DLG_LISTBOXEXAMPLE;
  16449.        pfnDlgProc = (PFNWP)fnwpListBoxDlg;
  16450.        break;
  16451.      case MI_ABOUTBOX:
  16452.        WinDlgBox(HWND_DESKTOP, hwnd, fnwpAboutBoxDlg, (HMODULE) NULL, DLG_ABOU
  16453.        return;
  16454.      default:
  16455.        return;
  16456.    }
  16457.    LoadDialog( HWND_DESKTOP,
  16458.                hwndFrame,
  16459.                idDlg,
  16460.                pfnDlgProc,
  16461.                *bModality );
  16462.    if( *bModality )
  16463.      WinInvalidateRect( hwnd, NULL, FALSE );  /* Request whole window repaint
  16464.  }
  16465.  
  16466.  /************************************************************************
  16467.  *
  16468.  *   FUNCTION: MainWndPaint
  16469.  *
  16470.  *   An unsophisticated window painting routine which simply repaints the
  16471.  *   entire window when a WM_PAINT message is received. In a real
  16472.  *   application more sophisticated techniques could be used to determine
  16473.  *   the minimum region needing repainting, and to paint only that
  16474.  *   region
  16475.  *
  16476.  ************************************************************************/
  16477.  
  16478.  VOID cdecl MainWndPaint( hwnd )
  16479.  HWND hwnd;
  16480.  {
  16481.    POINTL   pointl;
  16482.    HPS      hps;                          /* Presentation space handle */
  16483.    RECTL    rcl;                          /* Window rectangle          */
  16484.    CHAR     string[50];
  16485.  
  16486.    hps = WinBeginPaint( hwnd, (HPS)NULL, (PRECTL)&rcl );
  16487.    /*
  16488.          Color in the background
  16489.    */
  16490.    switch ((int) colorClient) {
  16491.          case 0:                /* (r,g,b) = (0,0,0) */
  16492.              WinFillRect( hps, (PRECTL)&rcl, CLR_BLACK );
  16493.              break;
  16494.          case 7:                /* (r,g,b) = (1,1,1) */
  16495.              WinFillRect( hps, (PRECTL)&rcl, CLR_WHITE );
  16496.              break;
  16497.          default:
  16498.              WinFillRect( hps, (PRECTL)&rcl, colorClient );
  16499.              break;
  16500.    }
  16501.    /*
  16502.          Set the text character colors
  16503.    */
  16504.    GpiSetColor( hps, (colorClient == 0L) ? CLR_WHITE
  16505.                                          : CLR_BLACK );
  16506.    pointl.x = 10L; pointl.y = 70L;
  16507.    strcpy( string, "Dialog modality    = " );
  16508.    strcat( string, (bModality) ? "Modal"
  16509.                                : "Modeless" );
  16510.    GpiCharStringAt( hps, &pointl, (LONG)strlen( string ), (PSZ)string );
  16511.    pointl.y = 50L;
  16512.    strcpy( string, "Entry Field 1      = " );
  16513.    strcat( string, szEntryField1 );
  16514.    GpiCharStringAt( hps, &pointl, (LONG)strlen( string ), (PSZ)string );
  16515.    pointl.y = 30L;
  16516.    strcpy( string, "Entry Field 2      = " );
  16517.    strcat( string, szEntryField2 );
  16518.    GpiCharStringAt( hps, &pointl, (LONG)strlen( string ), (PSZ)string );
  16519.    pointl.y = 10L;
  16520.    strcpy( string, "List Box Selection = " );
  16521.    strcat( string, szSelection );
  16522.    GpiCharStringAt( hps, &pointl, (LONG)strlen( string ), (PSZ)string );
  16523.    WinEndPaint( hps );
  16524.   }
  16525.  
  16526.  /**************************************************************************
  16527.  *
  16528.  *  FUNCTION: SetModality
  16529.  *
  16530.  *  Check or uncheck Modal and Modeless menu items as appropriate.
  16531.  *
  16532.  **************************************************************************/
  16533.  
  16534.  VOID cdecl SetModality( hwnd, bModal )
  16535.  HWND hwnd;
  16536.  BOOL bModal;
  16537.  {
  16538.    WinPostMsg( WinWindowFromID( hwnd, FID_MENU ),
  16539.                MM_SETITEMATTR,
  16540.                MPFROM2SHORT( MI_MODAL, TRUE ),
  16541.                MPFROM2SHORT( MIA_CHECKED, (bModal) ? ( MIA_CHECKED)
  16542.                                                    : (~MIA_CHECKED) ) );
  16543.  
  16544.    WinPostMsg( WinWindowFromID( hwnd, FID_MENU ),
  16545.                MM_SETITEMATTR,
  16546.                MPFROM2SHORT( MI_MODELESS, TRUE ),
  16547.                MPFROM2SHORT( MIA_CHECKED, (bModal) ? (~MIA_CHECKED)
  16548.                                                    : ( MIA_CHECKED) ) );
  16549.  
  16550.  }
  16551.  
  16552.  MRESULT EXPENTRY fnwpAboutBoxDlg(hDlg, msg, mp1, mp2)
  16553.  /*
  16554.      About... dialog procedure
  16555.  */
  16556.  HWND        hDlg;
  16557.  USHORT        msg;
  16558.  MPARAM        mp1;
  16559.  MPARAM        mp2;
  16560.  {
  16561.      switch(msg) {
  16562.          case WM_COMMAND:
  16563.              switch(COMMANDMSG(&msg)->cmd) {
  16564.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  16565.                  default: break;
  16566.              }
  16567.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  16568.      }
  16569.      return FALSE;
  16570.  }
  16571.  
  16572.  
  16573.  DMGDB.C
  16574.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGDB.C
  16575.  
  16576.  /****************************** Module Header ******************************\
  16577.  * Module Name: DMGDB.C
  16578.  *
  16579.  * DDE manager data handling routines
  16580.  *
  16581.  * Created: 12/14/88 Sanford Staab
  16582.  *
  16583.  * Copyright (c) 1988, 1989  Microsoft Corporation
  16584.  \***************************************************************************/
  16585.  #include "ddemlp.h"
  16586.  
  16587.  /***************************** Private Function ****************************\
  16588.  * PAPPINFO GetCurrentAppInfo()
  16589.  *
  16590.  * DESCRIPTION:
  16591.  * This routine uses the pid of the current thread to locate the information
  16592.  * pertaining to that thread.  If not found, 0 is returned.
  16593.  *
  16594.  * This call fails if the DLL is in a callback state to prevent recursion.
  16595.  * if fChkCallback is set.
  16596.  *
  16597.  * History:      1/1/89  Created         sanfords
  16598.  \***************************************************************************/
  16599.  PAPPINFO GetCurrentAppInfo(fChkCallback)
  16600.  BOOL fChkCallback;
  16601.  {
  16602.      PAPPINFO pai;
  16603.  
  16604.      SemEnter();
  16605.      if (pAppInfoList == NULL || !CheckSel(SELECTOROF(pAppInfoList))) {
  16606.          SemLeave();
  16607.          return(0);
  16608.      }
  16609.      pai = pAppInfoList;
  16610.      while (pai) {
  16611.          if (pai->pid == FSRSemDmg.pid && pai->tid == FSRSemDmg.tid) {
  16612.              if (fChkCallback && pai->cInCallback > MAX_RECURSE) {
  16613.                  pai->LastError = DMGERR_REENTRANCY;
  16614.                  break;
  16615.              } else {
  16616.                  SemLeave();
  16617.                  return(pai);
  16618.              }
  16619.          }
  16620.          pai = pai->next;
  16621.      }
  16622.      SemLeave();
  16623.      return(0);
  16624.  }
  16625.  
  16626.  
  16627.  /***************************** Private Function ****************************\
  16628.  * void UnlinkAppInfo(pai)
  16629.  * PAPPINFO pai;
  16630.  *
  16631.  * DESCRIPTION:
  16632.  *   unlinks an pai safely.  Does nothing if not linked.
  16633.  *
  16634.  * History:      1/1/89  Created         sanfords
  16635.  \***************************************************************************/
  16636.  void UnlinkAppInfo(pai)
  16637.  PAPPINFO pai;
  16638.  {
  16639.      PAPPINFO paiT;
  16640.  
  16641.      AssertF(pai != NULL, "UnlinkAppInfo - NULL input");
  16642.      SemEnter();
  16643.      if (pai == pAppInfoList) {
  16644.          pAppInfoList = pai->next;
  16645.          SemLeave();
  16646.          return;
  16647.      }
  16648.      paiT = pAppInfoList;
  16649.      while (paiT && paiT->next != pai)
  16650.          paiT = paiT->next;
  16651.      if (paiT)
  16652.          paiT->next = pai->next;
  16653.      SemLeave();
  16654.      return;
  16655.  }
  16656.  
  16657.  
  16658.  
  16659.  
  16660.  
  16661.  /***************************** Private Functions ***************************\
  16662.  * General List management functions.
  16663.  *
  16664.  * History:
  16665.  *   Created     12/15/88    sanfords
  16666.  \***************************************************************************/
  16667.  PLST CreateLst(hheap, cbItem)
  16668.  HHEAP hheap;
  16669.  USHORT cbItem;
  16670.  {
  16671.      PLST pLst;
  16672.  
  16673.      SemEnter();
  16674.      if (!(pLst = (PLST)FarAllocMem(hheap, sizeof(LST)))) {
  16675.          SemLeave();
  16676.          return(NULL);
  16677.      }
  16678.      pLst->hheap = hheap;
  16679.      pLst->cbItem = cbItem;
  16680.      pLst->pItemFirst = (PLITEM)NULL;
  16681.      SemLeave();
  16682.      return(pLst);
  16683.  }
  16684.  
  16685.  
  16686.  
  16687.  void FlushLst(pLst)
  16688.  PLST pLst;
  16689.  {
  16690.      if (pLst == NULL)
  16691.          return;
  16692.      SemEnter();
  16693.      while (pLst->pItemFirst)
  16694.          RemoveLstItem(pLst, pLst->pItemFirst);
  16695.      SemLeave();
  16696.  }
  16697.  
  16698.  
  16699.  
  16700.  void DestroyLst(pLst)
  16701.  PLST pLst;
  16702.  {
  16703.      if (pLst == NULL)
  16704.          return;
  16705.      SemEnter();
  16706.      while (pLst->pItemFirst)
  16707.          RemoveLstItem(pLst, pLst->pItemFirst);
  16708.      FarFreeMem(pLst->hheap, pLst, sizeof(LST));
  16709.      SemLeave();
  16710.  }
  16711.  
  16712.  
  16713.  
  16714.  PLITEM FindLstItem(pLst, npfnCmp, piSearch)
  16715.  PLST pLst;
  16716.  NPFNCMP npfnCmp;
  16717.  PLITEM piSearch;
  16718.  {
  16719.      PLITEM pi;
  16720.  
  16721.      if (pLst == NULL)
  16722.          return(NULL);
  16723.      SemEnter();
  16724.      pi = pLst->pItemFirst;
  16725.      while (pi) {
  16726.          if ((*npfnCmp)
  16727.                  ((PBYTE)pi + sizeof(LITEM), (PBYTE)piSearch + sizeof(LITEM)))
  16728.              SemLeave();
  16729.              return(pi);
  16730.          }
  16731.          pi = pi->next;
  16732.      }
  16733.      SemLeave();
  16734.  }
  16735.  
  16736.  
  16737.  
  16738.  /*
  16739.   * Comparison functions for FindLstItem() and FindPileItem()
  16740.   */
  16741.  
  16742.  BOOL CmpULONG(pb1, pb2)
  16743.  PBYTE pb1;
  16744.  PBYTE pb2;
  16745.  {
  16746.      return(*(PULONG)pb1 == *(PULONG)pb2);
  16747.  }
  16748.  
  16749.  BOOL CmppHsz(pb1, pb2)
  16750.  PBYTE pb1;
  16751.  PBYTE pb2;
  16752.  {
  16753.      return(CmpHsz(*(PHSZ)pb1, *(PHSZ)pb2) ? FALSE : TRUE);
  16754.  }
  16755.  
  16756.  
  16757.  
  16758.  
  16759.  /***************************** Private Function ****************************\
  16760.  * This routine creates a new list item for pLst and links it in according
  16761.  * to the ILST_ constant in afCmd.  Returns a pointer to the new item
  16762.  * or NULL on failure.
  16763.  *
  16764.  * Note:  This MUST be in the semaphore for use since the new list item
  16765.  * is filled with garbage on return yet is linked in.
  16766.  *
  16767.  *
  16768.  * History:
  16769.  *   Created     9/12/89    Sanfords
  16770.  \***************************************************************************/
  16771.  PLITEM NewLstItem(pLst, afCmd)
  16772.  PLST pLst;
  16773.  USHORT afCmd;
  16774.  {
  16775.      PLITEM pi, piT;
  16776.  
  16777.      if (pLst == NULL)
  16778.          return(NULL);
  16779.      SemCheckIn();
  16780.  
  16781.      pi = (PLITEM)FarAllocMem(pLst->hheap, pLst->cbItem + sizeof(LITEM));
  16782.      if (pi == NULL) {
  16783.          AssertF(FALSE, "NewLstItem - memory failure");
  16784.          return(NULL);
  16785.      }
  16786.  
  16787.      if (afCmd & ILST_NOLINK)
  16788.          return(pi);
  16789.  
  16790.      if (((piT = pLst->pItemFirst) == NULL) || (afCmd & ILST_FIRST)) {
  16791.          pi->next = piT;
  16792.          pLst->pItemFirst = pi;
  16793.      } else {                            /* ILST_LAST assumed */
  16794.          while (piT->next != NULL)
  16795.              piT = piT->next;
  16796.          piT->next = pi;
  16797.          pi->next = NULL;
  16798.      }
  16799.      return(pi);
  16800.  }
  16801.  
  16802.  
  16803.  
  16804.  /***************************** Private Function ****************************\
  16805.  * This routine unlinks and frees pi from pLst.  If pi cannot be located
  16806.  * within pLst, it is freed anyway.
  16807.  *
  16808.  * History:
  16809.  *   Created     9/12/89    Sanfords
  16810.  \***************************************************************************/
  16811.  BOOL RemoveLstItem(pLst, pi)
  16812.  PLST pLst;
  16813.  PLITEM pi;
  16814.  {
  16815.      PLITEM piT;
  16816.  
  16817.      if (pLst == NULL || pi == NULL)
  16818.          return(FALSE);
  16819.  
  16820.      SemCheckIn();
  16821.  
  16822.      if ((piT = pLst->pItemFirst) != NULL) {
  16823.          if (pi == piT) {
  16824.              pLst->pItemFirst = pi->next;
  16825.          } else {
  16826.              while (piT->next != pi && piT->next != NULL)
  16827.                  piT = piT->next;
  16828.              if (piT->next != NULL)
  16829.                  piT->next = pi->next; /* unlink */
  16830.          }
  16831.      } else {
  16832.          AssertF(pi == NULL, "Improper list item removal");
  16833.      }
  16834.      FarFreeMem(pLst->hheap, pi, pLst->cbItem + sizeof(LITEM));
  16835.      return(TRUE);
  16836.  }
  16837.  
  16838.  
  16839.  
  16840.  /***************************** Private Function ****************************\
  16841.  * This routine uses ILST_ constants to insert a list item into the apropriate
  16842.  * spot of the pLst given.  Only ILST_FIRST or ILST_LAST are allowed.
  16843.  *
  16844.  * History:
  16845.  *   Created     9/11/89    Sanfords
  16846.  \***************************************************************************/
  16847.  BOOL InsertLstItem(pLst, pi, afCmd)
  16848.  PLST pLst;
  16849.  PLITEM pi;
  16850.  USHORT afCmd;
  16851.  {
  16852.      PLITEM piT;
  16853.  
  16854.      if (pLst == NULL)
  16855.          return(FALSE);
  16856.  
  16857.      SemEnter();
  16858.  
  16859.      if (pLst->pItemFirst == NULL || afCmd & ILST_FIRST) {
  16860.          pi->next = pLst->pItemFirst;
  16861.          pLst->pItemFirst = pi;
  16862.      } else {                    /* ILST_LAST assumed */
  16863.          piT = pLst->pItemFirst;
  16864.          while (piT->next)
  16865.              piT = piT->next;
  16866.          piT->next = pi;
  16867.          pi->next = NULL;
  16868.      }
  16869.  
  16870.      SemLeave();
  16871.      return(TRUE);
  16872.  }
  16873.  
  16874.  
  16875.  
  16876.  
  16877.  /*
  16878.   * ------------- Specific list routines -------------
  16879.   */
  16880.  
  16881.  /*
  16882.   * This function is HIGHLY dependent on the ADVLI structure.
  16883.   * This will match an exact hsz/fmt pair with a 0 format being wild.
  16884.   */
  16885.  BOOL CmpAdv(pb1, pb2)
  16886.  PBYTE pb1;
  16887.  PBYTE pb2;
  16888.  {
  16889.      USHORT usFmt;
  16890.  
  16891.      if (*(PHSZ)pb1 == *(PHSZ)pb2) {
  16892.          if ((usFmt = *(PUSHORT)(pb2 + 4)) == 0)
  16893.              return(TRUE);
  16894.          if (usFmt == *(PUSHORT)(pb1 + 4))
  16895.              return(TRUE);
  16896.      }
  16897.      return(FALSE);
  16898.  }
  16899.  
  16900.  
  16901.  
  16902.  BOOL fSearchHwndList(pLst, hwnd)
  16903.  PLST pLst;
  16904.  HWND hwnd;
  16905.  {
  16906.      HWNDLI hwndi;
  16907.  
  16908.      hwndi.hwnd = hwnd;
  16909.      return((BOOL)FindLstItem(pLst, CmpHwnd, (PLITEM)&hwndi));
  16910.  }
  16911.  
  16912.  
  16913.  
  16914.  void AddHwndList(hwnd, pLst)
  16915.  HWND hwnd;
  16916.  PLST pLst;
  16917.  {
  16918.      HWNDLI hwndli;
  16919.      PHWNDLI pli;
  16920.  
  16921.      AssertF(pLst != NULL, "AddHwndList - NULL pLst");
  16922.      AssertF(pLst->cbItem == sizeof(HWNDLI), "AddHwndList - Bad item size");
  16923.      SemEnter();
  16924.      hwndli.hwnd = hwnd;
  16925.      if ((hwnd == NULL) || FindLstItem(pLst, CmpHwnd, (PLITEM)&hwndli)) {
  16926.          SemLeave();
  16927.          return;
  16928.      }
  16929.      pli = (PHWNDLI)NewLstItem(pLst, ILST_FIRST);
  16930.      pli->hwnd = hwnd;
  16931.      SemLeave();
  16932.  }
  16933.  
  16934.  
  16935.  
  16936.  /*
  16937.   * Insert the given data into the list if one does not already exist
  16938.   * under the given hwnd.
  16939.   */
  16940.  void AddAckHwndList(hwnd, hszApp, hszTopic, pLst)
  16941.  HWND hwnd;
  16942.  HSZ hszApp;
  16943.  HSZ hszTopic;
  16944.  PLST pLst;
  16945.  {
  16946.      HWNDLI hwndli;
  16947.      PACKHWNDLI pli;
  16948.  
  16949.      AssertF(pLst != NULL, "AddAckHwndList - NULL pLst");
  16950.      AssertF(pLst->cbItem == sizeof(ACKHWNDLI), "AddAckHwndList - Bad item siz
  16951.      SemEnter();
  16952.      hwndli.hwnd = hwnd;
  16953.      if ((hwnd == NULL) || FindLstItem(pLst, CmpHwnd, (PLITEM)&hwndli)) {
  16954.          SemLeave();
  16955.          return;
  16956.      }
  16957.      pli = (PACKHWNDLI)NewLstItem(pLst, ILST_FIRST);
  16958.      pli->hwnd = hwnd;
  16959.      pli->hszApp = hszApp;
  16960.      pli->hszTopic = hszTopic;
  16961.      SemLeave();
  16962.  }
  16963.  
  16964.  
  16965.  
  16966.  
  16967.  /***************************** Private Function ****************************\
  16968.  * hwnd-hsz list functions
  16969.  *
  16970.  * History:      1/20/89     Created         sanfords
  16971.  \***************************************************************************/
  16972.  void AddHwndHszList(hsz, hwnd, pLst)
  16973.  HSZ hsz;
  16974.  HWND hwnd;
  16975.  PLST pLst;
  16976.  {
  16977.      PHWNDHSZLI phhi;
  16978.  
  16979.      AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "AddHwndHszList - Bad item siz
  16980.      SemEnter();
  16981.      if ((hsz == NULL) || (BOOL)HwndFromHsz(hsz, pLst)) {
  16982.          SemLeave();
  16983.          return;
  16984.      }
  16985.      phhi = (PHWNDHSZLI)NewLstItem(pLst, ILST_FIRST);
  16986.      phhi->hwnd = hwnd;
  16987.      phhi->hsz = hsz;
  16988.      IncHszCount(hsz);
  16989.      SemLeave();
  16990.  }
  16991.  
  16992.  
  16993.  void DestroyHwndHszList(pLst)
  16994.  PLST pLst;
  16995.  {
  16996.      AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "DestroyHwndHszList - Bad item
  16997.      SemEnter();
  16998.      while(pLst->pItemFirst) {
  16999.          FreeHsz(((PHWNDHSZLI)pLst->pItemFirst)->hsz);
  17000.          RemoveLstItem(pLst, pLst->pItemFirst);
  17001.      }
  17002.      FarFreeMem(pLst->hheap, pLst, sizeof(LST));
  17003.      SemLeave();
  17004.  }
  17005.  
  17006.  
  17007.  
  17008.  HWND HwndFromHsz(hsz, pLst)
  17009.  HSZ hsz;
  17010.  PLST pLst;
  17011.  {
  17012.      HWNDHSZLI hhli;
  17013.      PHWNDHSZLI phhli;
  17014.  
  17015.      hhli.hsz = hsz;
  17016.      if (!(phhli = (PHWNDHSZLI)FindLstItem(pLst, CmppHsz, (PLITEM)&hhli)))
  17017.          return(NULL);
  17018.      return(phhli->hwnd);
  17019.  }
  17020.  
  17021.  
  17022.  
  17023.  /***************************** Private Function ****************************\
  17024.  * DESCRIPTION:
  17025.  *   Advise list helper functions.
  17026.  *
  17027.  * History:      1/20/89     Created         sanfords
  17028.  \***************************************************************************/
  17029.  BOOL AddAdvList(pLst, hszItem, fsStatus, usFmt)
  17030.  PLST pLst;
  17031.  HSZ hszItem;
  17032.  USHORT fsStatus;
  17033.  USHORT usFmt;
  17034.  {
  17035.      PADVLI pali;
  17036.  
  17037.      AssertF(pLst->cbItem == sizeof(ADVLI), "AddAdvList - bad item size");
  17038.      if (hszItem == NULL)
  17039.          return(TRUE);
  17040.      SemEnter();
  17041.      if (!(pali = FindAdvList(pLst, hszItem, usFmt))) {
  17042.          IncHszCount(hszItem);
  17043.          pali = (PADVLI)NewLstItem(pLst, ILST_FIRST);
  17044.      }
  17045.      AssertF((BOOL)pali, "AddAdvList - NewLstItem() failed")
  17046.      if (pali != NULL) {
  17047.          pali->hszItem = hszItem;
  17048.          pali->usFmt = usFmt;
  17049.          pali->fsStatus = fsStatus;
  17050.      }
  17051.      SemLeave();
  17052.      return((BOOL)pali);
  17053.  }
  17054.  
  17055.  
  17056.  
  17057.  /*
  17058.   * This will delete the matching Advise loop entry.  If usFmt is 0, all
  17059.   * entries with the same hszItem are deleted.  Returns fNotEmptyAfterDelete.
  17060.   */
  17061.  BOOL DeleteAdvList(pLst, hszItem, usFmt)
  17062.  PLST pLst;
  17063.  HSZ hszItem;
  17064.  USHORT usFmt;
  17065.  {
  17066.      PADVLI pali;
  17067.  
  17068.      if (hszItem == NULL)
  17069.          return((BOOL)pLst->pItemFirst);
  17070.      SemEnter();
  17071.      while (pali = (PADVLI)FindAdvList(pLst, hszItem, usFmt)) {
  17072.          FreeHsz((pali)->hszItem);
  17073.          RemoveLstItem(pLst, (PLITEM)pali);
  17074.      }
  17075.      SemLeave();
  17076.      return((BOOL)pLst->pItemFirst);
  17077.  }
  17078.  
  17079.  
  17080.  
  17081.  /***************************** Private Function ****************************\
  17082.  * This routine searches the advise list for and entry in hszItem.  It returns
  17083.  * pAdvli only if the item is found.
  17084.  *
  17085.  * History:
  17086.  *   Created     9/12/89    Sanfords
  17087.  \***************************************************************************/
  17088.  PADVLI FindAdvList(pLst, hszItem, usFmt)
  17089.  PLST pLst;
  17090.  HSZ hszItem;
  17091.  USHORT usFmt;
  17092.  {
  17093.      ADVLI advli;
  17094.  
  17095.      advli.hszItem = hszItem;
  17096.      advli.usFmt = usFmt;
  17097.      return((PADVLI)FindLstItem(pLst, CmpAdv, (PLITEM)&advli));
  17098.  }
  17099.  
  17100.  
  17101.  /***************************** Private Function ****************************\
  17102.  * This routine searches for the next entry for hszItem.  It returns
  17103.  * pAdvli only if the item is found.
  17104.  *
  17105.  * History:
  17106.  *   Created     11/15/89    Sanfords
  17107.  \***************************************************************************/
  17108.  PADVLI FindNextAdv(padvli, hszItem)
  17109.  PADVLI padvli;
  17110.  HSZ hszItem;
  17111.  {
  17112.  
  17113.      SemEnter();
  17114.      while ((padvli = (PADVLI)padvli->next) != NULL) {
  17115.          if (padvli->hszItem == hszItem) {
  17116.              SemLeave();
  17117.              return(padvli);
  17118.          }
  17119.      }
  17120.      SemLeave();
  17121.      return(NULL);
  17122.  }
  17123.  
  17124.  
  17125.  
  17126.  /***************************** Pile Functions *******************************
  17127.  *
  17128.  *  A pile is a list where each item is an array of subitems.  This allows
  17129.  *  a more memory efficient method of handling unordered lists.
  17130.  *
  17131.  \****************************************************************************
  17132.  
  17133.  PPILE CreatePile(hheap, cbItem, cItemsPerBlock)
  17134.  HHEAP hheap;
  17135.  USHORT cbItem;
  17136.  USHORT cItemsPerBlock;
  17137.  {
  17138.      PPILE ppile;
  17139.  
  17140.      if (!(ppile = (PPILE)FarAllocMem(hheap, sizeof(PILE)))) {
  17141.          SemLeave();
  17142.          return(NULL);
  17143.      }
  17144.      ppile->pBlockFirst = (PLITEM)NULL;
  17145.      ppile->hheap = hheap;
  17146.      ppile->cbBlock = cbItem * cItemsPerBlock + sizeof(PILEB);
  17147.      ppile->cSubItemsMax = cItemsPerBlock;
  17148.      ppile->cbSubItem = cbItem;
  17149.      return(ppile);
  17150.  }
  17151.  
  17152.  
  17153.  PPILE DestroyPile(pPile)
  17154.  PPILE pPile;
  17155.  {
  17156.      if (pPile == NULL)
  17157.          return(NULL);
  17158.      SemEnter();
  17159.      while (pPile->pBlockFirst)
  17160.          RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
  17161.      FarFreeMem(pPile->hheap, pPile, sizeof(PILE));
  17162.      SemLeave();
  17163.      return(NULL);
  17164.  }
  17165.  
  17166.  void FlushPile(pPile)
  17167.  PPILE pPile;
  17168.  {
  17169.      if (pPile == NULL)
  17170.          return;
  17171.      SemEnter();
  17172.      while (pPile->pBlockFirst)
  17173.          RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
  17174.      SemLeave();
  17175.  }
  17176.  
  17177.  
  17178.  USHORT QPileItemCount(pPile)
  17179.  PPILE pPile;
  17180.  {
  17181.      register USHORT c;
  17182.      PPILEB pBlock;
  17183.  
  17184.      if (pPile == NULL)
  17185.          return(0);
  17186.  
  17187.      SemEnter();
  17188.      pBlock = pPile->pBlockFirst;
  17189.      c = 0;
  17190.      while (pBlock) {
  17191.          c += pBlock->cItems;
  17192.          pBlock = pBlock->next;
  17193.      }
  17194.      SemLeave();
  17195.      return(c);
  17196.  }
  17197.  
  17198.  
  17199.  BOOL CopyPileItems(pPile, pDst)
  17200.  PPILE pPile;
  17201.  PBYTE pDst;
  17202.  {
  17203.      PPILEB pBlock;
  17204.  
  17205.      AssertF(pDst != NULL, "CopyPileItems - NULL destination");
  17206.      if (pPile == NULL)
  17207.          return(FALSE);
  17208.  
  17209.      SemEnter();
  17210.      pBlock = pPile->pBlockFirst;
  17211.      while (pBlock) {
  17212.          CopyBlock((PBYTE)pBlock + sizeof(PILEB), pDst,
  17213.                  pBlock->cItems * pPile->cbSubItem);
  17214.          pDst += pBlock->cItems * pPile->cbSubItem;
  17215.          pBlock = pBlock->next;
  17216.      }
  17217.      SemLeave();
  17218.  
  17219.      return(TRUE);
  17220.  }
  17221.  
  17222.  
  17223.  
  17224.  
  17225.  /***************************** Private Function ****************************\
  17226.  * Locate and return the pointer to the pile subitem who's key fields match
  17227.  * pbSearch using npfnCmp to compare the fields.  If pbSearch == NULL, or
  17228.  * npfnCmp == NULL, the first subitem is returned.
  17229.  *
  17230.  * afCmd may be:
  17231.  * FPI_DELETE - delete the located item
  17232.  * FPI_COUNT - count number of items that match
  17233.  * In this case, the returned pointer is not valid.
  17234.  *
  17235.  * pppb points to where to store a pointer to the block which contained
  17236.  * the located item.
  17237.  *
  17238.  * if pppb == NULL, it is ignored.
  17239.  *
  17240.  * NULL is returned if pbSearch was not found or if the list was empty.
  17241.  *
  17242.  * History:
  17243.  *   Created     9/12/89    Sanfords
  17244.  \***************************************************************************/
  17245.  PBYTE FindPileItem(pPile, npfnCmp, pbSearch, afCmd)
  17246.  PPILE pPile;
  17247.  NPFNCMP npfnCmp;
  17248.  PBYTE pbSearch;
  17249.  USHORT afCmd;
  17250.  {
  17251.      PBYTE pb;
  17252.      PPILEB ppbT;
  17253.      register int i;
  17254.      register int c;
  17255.  
  17256.      if (pPile == NULL)
  17257.          return(NULL);
  17258.      c = 0;
  17259.      SemEnter();
  17260.      ppbT = pPile->pBlockFirst;
  17261.      while (ppbT) {
  17262.          /*
  17263.           * for each block...
  17264.           */
  17265.          for (pb = (PBYTE)ppbT + sizeof(PILEB), i = 0;
  17266.                  i < ppbT->cItems; pb += pPile->cbSubItem, i++) {
  17267.              /*
  17268.               * and each item within that block..
  17269.               */
  17270.              if (pbSearch == NULL || npfnCmp == NULL ||
  17271.                      (*npfnCmp)(pb, pbSearch)) {
  17272.                  /*
  17273.                   * If it matches or we don't care...
  17274.                   */
  17275.                  if (afCmd & FPI_DELETE) {
  17276.                      /*
  17277.                       * remove entire block if this was the last subitem in it
  17278.                       */
  17279.                      if (--ppbT->cItems == 0) {
  17280.                          RemoveLstItem((PLST)pPile, (PLITEM)ppbT);
  17281.                      } else {
  17282.                          /*
  17283.                           * copy last subitem in the block over the removed it
  17284.                           */
  17285.                          CopyBlock((PBYTE)ppbT + sizeof(PILEB) +
  17286.                                  pPile->cbSubItem * ppbT->cItems,
  17287.                                  pb, pPile->cbSubItem);
  17288.                      }
  17289.                  }
  17290.                  if (afCmd & FPI_COUNT) {
  17291.                      c++;
  17292.                  } else {
  17293.                      SemLeave();
  17294.                      return(pb);
  17295.                  }
  17296.                  if (afCmd & FPI_DELETE) {
  17297.                      pb = (PBYTE)ppbT + sizeof(PILEB);
  17298.                      i = 0;
  17299.                  }
  17300.              }
  17301.          }
  17302.          ppbT = (PPILEB)ppbT->next;
  17303.      }
  17304.      SemLeave();
  17305.      return((PBYTE)(ULONG)c);
  17306.  }
  17307.  
  17308.  
  17309.  /***************************** Private Function ****************************\
  17310.  * Places a copy of the subitem pointed to by pb into the first available
  17311.  * spot in the pile pPile.  If npfnCmp != NULL, the pile is first searched
  17312.  * for a pb match.  If found, pb replaces the located data but FALSE is
  17313.  * returned to show that no real addition took place.
  17314.  *
  17315.  * History:
  17316.  *   Created     9/12/89    Sanfords
  17317.  \***************************************************************************/
  17318.  BOOL AddPileItem(pPile, pb, npfnCmp)
  17319.  PPILE pPile;
  17320.  PBYTE pb;
  17321.  BOOL (*npfnCmp)(PBYTE pb, PBYTE pbSearch);
  17322.  {
  17323.      PBYTE pbDst;
  17324.      PPILEB ppb;
  17325.  
  17326.      if (pPile == NULL)
  17327.          return(FALSE);
  17328.      SemEnter();
  17329.      if (npfnCmp != NULL &&
  17330.              (pbDst = FindPileItem(pPile, npfnCmp, pb, 0)) != NULL) {
  17331.          CopyBlock(pb, pbDst, pPile->cbSubItem);
  17332.          SemLeave();
  17333.          return(FALSE);
  17334.      }
  17335.      ppb = pPile->pBlockFirst;
  17336.      /*
  17337.       * locate a block with room
  17338.       */
  17339.      while ((ppb != NULL) && ppb->cItems == pPile->cSubItemsMax) {
  17340.          ppb = (PPILEB)ppb->next;
  17341.      }
  17342.      /*
  17343.       * If all full or no blocks, make a new one, link it on the bottom.
  17344.       */
  17345.      if (ppb == NULL) {
  17346.          if ((ppb = (PPILEB)NewLstItem((PLST)pPile, ILST_LAST)) == NULL) {
  17347.              SemLeave();
  17348.              return(FALSE);
  17349.          }
  17350.          ppb->cItems = 0;
  17351.      }
  17352.      /*
  17353.       * add the subitem
  17354.       */
  17355.      CopyBlock(pb, (PBYTE)ppb + sizeof(PILEB) + pPile->cbSubItem * ppb->cItems
  17356.          pPile->cbSubItem);
  17357.  
  17358.      SemLeave();
  17359.      return(TRUE);
  17360.  }
  17361.  
  17362.  
  17363.  
  17364.  
  17365.  /***************************** Private Function ****************************\
  17366.  * Fills pb with a copy of the top item's data and removes it from the pile.
  17367.  * returns FALSE if the pile was empty.
  17368.  *
  17369.  * History:
  17370.  *   Created     9/12/89    Sanfords
  17371.  \***************************************************************************/
  17372.  BOOL PopPileSubitem(pPile, pb)
  17373.  PPILE pPile;
  17374.  PBYTE pb;
  17375.  {
  17376.      PPILEB ppb;
  17377.      PBYTE pSrc;
  17378.  
  17379.  
  17380.      if ((pPile == NULL) || ((ppb = pPile->pBlockFirst) == NULL))
  17381.          return(FALSE);
  17382.  
  17383.      SemEnter();
  17384.      pSrc = (PBYTE)pPile->pBlockFirst + sizeof(PILEB);
  17385.      CopyBlock(pSrc, pb, pPile->cbSubItem);
  17386.      /*
  17387.       * remove entire block if this was the last subitem in it.
  17388.       */
  17389.      if (pPile->pBlockFirst->cItems == 1) {
  17390.          RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
  17391.      } else {
  17392.          /*
  17393.           * move last item in block to replace copied subitem and decrement
  17394.           * subitem count.
  17395.           */
  17396.          CopyBlock(pSrc + pPile->cbSubItem * --pPile->pBlockFirst->cItems,
  17397.                  pSrc, pPile->cbSubItem);
  17398.      }
  17399.      SemLeave();
  17400.      return(TRUE);
  17401.  }
  17402.  
  17403.  
  17404.  /***************************** Semaphore Functions *************************\
  17405.  * SemEnter() and SemLeave() are macros.
  17406.  *
  17407.  * History:      1/1/89  Created         sanfords
  17408.  \***************************************************************************/
  17409.  void SemInit()
  17410.  {
  17411.      PBYTE pSem;
  17412.      SHORT c;
  17413.  
  17414.      pSem = (PBYTE)&FSRSemDmg;
  17415.      c = 0;
  17416.      while (c++ < sizeof(DOSFSRSEM)) {
  17417.          *pSem++ = 0;
  17418.      }
  17419.      FSRSemDmg.cb = sizeof(DOSFSRSEM);
  17420.  }
  17421.  
  17422.  #ifdef DEBUG
  17423.  void SemCheckIn()
  17424.  {
  17425.      PIDINFO pi;
  17426.      BOOL fin;
  17427.  
  17428.      DosGetPID(&pi);
  17429.      fin = (FSRSemDmg.cUsage > 0) &&
  17430.              (FSRSemDmg.pid == pi.pid) &&
  17431.              ((FSRSemDmg.tid == pi.tid) || (FSRSemDmg.tid == -1));
  17432.      /*
  17433.       * !!! NOTE: during exitlists processing, semaphore TIDs are set to -1
  17434.       */
  17435.      AssertF(fin, "SemCheckIn - Out of Semaphore");
  17436.      if (!fin)
  17437.          SemEnter();
  17438.  }
  17439.  
  17440.  void SemCheckOut()
  17441.  {
  17442.      PIDINFO pi;
  17443.      BOOL fOut;
  17444.  
  17445.      DosGetPID(&pi);
  17446.      fOut = FSRSemDmg.cUsage == 0 || FSRSemDmg.pid != pi.pid ||
  17447.                  FSRSemDmg.tid != pi.tid;
  17448.      AssertF(fOut, "SemCheckOut - In Semaphore");
  17449.      if (!fOut)
  17450.          while (FSRSemDmg.cUsage)
  17451.              SemLeave();
  17452.  
  17453.  }
  17454.  #endif
  17455.  
  17456.  
  17457.  void SemEnter()
  17458.  {
  17459.      DosFSRamSemRequest(&FSRSemDmg, SEM_INDEFINITE_WAIT);
  17460.  }
  17461.  
  17462.  
  17463.  void SemLeave()
  17464.  {
  17465.      DosFSRamSemClear(&FSRSemDmg);
  17466.  }
  17467.  
  17468.  
  17469.  
  17470.  void EXPENTRY ExlstAbort(usTermCode)
  17471.  USHORT usTermCode;
  17472.  {
  17473.      PAPPINFO pai;
  17474.      usTermCode;
  17475.  
  17476.      SemEnter();     /* get any other processes out of the semaphore */
  17477.      if (pai = GetCurrentAppInfo(FALSE)) {
  17478.          pai->cInCallback = 0;  /* so Unregister call will work */
  17479.          DdeUninitialize();
  17480.      } else {
  17481.          SemLeave();
  17482.          DosExitList(EXLST_REMOVE, (PFNEXITLIST)ExlstAbort);
  17483.      }
  17484.      DosExitList(EXLST_EXIT, 0);
  17485.  }
  17486.  
  17487.  BOOL CopyHugeBlock(pSrc, pDst, cb)
  17488.  PBYTE pSrc;
  17489.  PBYTE pDst;
  17490.  ULONG cb;
  17491.  {
  17492.      ULONG cFirst;
  17493.      /*
  17494.       *  |____________|   |___________|   |____________|  |____________|
  17495.       *     ^src                                 ^
  17496.       *
  17497.       *  |____________|   |___________|   |____________|  |____________|
  17498.       *             ^dst                                   ^
  17499.       */
  17500.      cFirst = (ULONG)min((~(USHORT)pSrc), (~(USHORT)pDst)) + 1L;
  17501.      if (cb < cFirst) {
  17502.          CopyBlock(pSrc, pDst, (USHORT)cb);
  17503.          return(TRUE);
  17504.      }
  17505.  
  17506.      goto copyit;
  17507.  
  17508.      /*
  17509.       * Now at least one of the pointers is on a segment boundry.
  17510.       */
  17511.      while (cb) {
  17512.          cFirst = min(0x10000 - ((USHORT)pSrc | (USHORT)pDst), cb);
  17513.  copyit:
  17514.          if (HIUSHORT(cFirst)) {
  17515.              /*
  17516.               * special case where pSrc and pDst both are on segment
  17517.               * bounds.  Copy half at a time.
  17518.               */
  17519.              /*
  17520.               *  |___________|   |____________|  |____________|
  17521.               *  ^src                               ^
  17522.               *
  17523.               *  |___________|   |____________|  |____________|
  17524.               *  ^dst                               ^
  17525.               */
  17526.              cFirst >>= 1;
  17527.              CopyBlock(pSrc, pDst, (USHORT)cFirst);
  17528.              pSrc += cFirst;
  17529.              pDst += cFirst;
  17530.              cb -= cFirst;
  17531.          }
  17532.          CopyBlock(pSrc, pDst, (USHORT)cFirst);
  17533.          pSrc = HugeOffset(pSrc, cFirst);
  17534.          pDst = HugeOffset(pDst, cFirst);
  17535.          cb -= cFirst;
  17536.      /*
  17537.       *  |____________|   |___________|   |____________|  |____________|
  17538.       *           ^src                           ^
  17539.       *
  17540.       *  |____________|   |___________|   |____________|  |____________|
  17541.       *                   ^dst                             ^
  17542.       */
  17543.      }
  17544.      return(TRUE);
  17545.  }
  17546.  
  17547.  
  17548.  
  17549.  
  17550.  /***************************************************************************\
  17551.  * Kills windows but avoids invalid window rips in debugger.
  17552.  \***************************************************************************/
  17553.  BOOL DestroyWindow(hwnd)
  17554.  HWND hwnd;
  17555.  {
  17556.      if (WinIsWindow(DMGHAB, hwnd))
  17557.          return(WinDestroyWindow(hwnd));
  17558.      return(TRUE);
  17559.  }
  17560.  
  17561.  
  17562.  /***************************** Private Function ****************************\
  17563.  * Returns hConv of the window passed in is one of the ddeml windows.
  17564.  *
  17565.  * History:
  17566.  *   Created     9/1/89    Sanfords
  17567.  \***************************************************************************/
  17568.  HCONV IsDdeWindow(hwnd)
  17569.  HWND hwnd;
  17570.  {
  17571.      PAPPINFO pai;
  17572.  
  17573.      pai = pAppInfoList;
  17574.  
  17575.      while (pai && WinIsChild(hwnd, pai->hwndDmg))
  17576.          pai = pai->next;
  17577.  
  17578.      if (pai)
  17579.          return((HCONV)hwnd);
  17580.      else
  17581.          return(0L);
  17582.  }
  17583.  
  17584.  
  17585.  /***************************** Private Function ****************************\
  17586.  * This routine only frees a MYDDES segment if this process is not the owner.
  17587.  *
  17588.  * History:
  17589.  *   Created     9/12/89    Sanfords
  17590.  \***************************************************************************/
  17591.  void FreeData(
  17592.  PMYDDES pmyddes,
  17593.  PAPPINFO pai)
  17594.  {
  17595.      TID tid;
  17596.      if (!CheckSel(SELECTOROF(pmyddes)) ||
  17597.              (   pmyddes->offszItemName == sizeof(MYDDES) &&
  17598.                  pmyddes->magic == MYDDESMAGIC &&
  17599.                  pmyddes->fs & HDATA_APPOWNED &&
  17600.                  pmyddes->pai == pai) )
  17601.          return;
  17602.  
  17603.      SemEnter();
  17604.      FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&pmyddes, FPI_DELETE);
  17605.      tid = pai->tid;
  17606.      do {
  17607.          if (FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&pmyddes, FPI_COUN
  17608.              SemLeave();
  17609.              return;
  17610.          }
  17611.          pai = pai->nextThread;
  17612.      } while (pai && pai->tid != tid);
  17613.      SemLeave();
  17614.      DosFreeSeg(SELECTOROF(pmyddes));
  17615.  }
  17616.  
  17617.  
  17618.  
  17619.  #ifdef DEBUG
  17620.  int APIENTRY DebugOutput(PCH);
  17621.  void fAssert(f, pszComment, line, szfile)
  17622.  BOOL f;
  17623.  PSZ pszComment;
  17624.  USHORT line;
  17625.  PSZ szfile;
  17626.  {
  17627.      char szT[90];
  17628.      PSZ psz, pszLast;
  17629.  
  17630.      if (!f) {
  17631.          szT[0] = '\000';
  17632.          psz = szT;
  17633.          pszLast = &szT[89];
  17634.          psz = lstrcat(psz, "\n\rAssertion failure: ", pszLast);
  17635.          psz = lstrcat(psz, szfile, pszLast);
  17636.          psz = lstrcat(psz, ":", pszLast);
  17637.          psz = dtoa(psz, line, FALSE);
  17638.          psz = lstrcat(psz, " ", pszLast);
  17639.          psz = lstrcat(psz, pszComment, pszLast);
  17640.          psz = lstrcat(psz, "\n\r", pszLast);
  17641.          DebugOutput(szT);
  17642.          DebugBreak();
  17643.      }
  17644.  }
  17645.  #endif
  17646.  
  17647.  
  17648.  
  17649.  HDMGDATA PutData(pSrc, cb, cbOff, hszItem, usFmt, afCmd, pai)
  17650.  PBYTE pSrc;
  17651.  ULONG cb;
  17652.  ULONG cbOff;
  17653.  HSZ hszItem;
  17654.  USHORT usFmt;
  17655.  USHORT afCmd;
  17656.  PAPPINFO pai;
  17657.  {
  17658.      PMYDDES pmyddes;
  17659.  
  17660.      if ((pmyddes = (PMYDDES)AllocDDESel(0, usFmt, hszItem, cb + cbOff, pai))
  17661.              == NULL) {
  17662.          pai->LastError = DMGERR_MEMORY_ERROR;
  17663.          return(0L);
  17664.      }
  17665.      pmyddes->fs = afCmd;
  17666.  
  17667.      if (afCmd & HDATA_APPFREEABLE) {
  17668.          if (!AddPileItem(pai->pHDataPile, (PBYTE)&pmyddes, CmpULONG)) {
  17669.              DosFreeSeg(SELECTOROF(pmyddes));
  17670.              pai->LastError = DMGERR_MEMORY_ERROR;
  17671.              return(0L);
  17672.          }
  17673.      }
  17674.      if (pSrc)
  17675.          CopyHugeBlock(pSrc, HugeOffset(DDES_PABDATA(pmyddes), cbOff), cb);
  17676.      return(pmyddes);
  17677.  }
  17678.  
  17679.  
  17680.  /*
  17681.   * This routine adds all HSZ/HAPP pairs it finds for the given pai matching
  17682.   * hszApp to hDataAdd.
  17683.   * poffAdd is the offset into the hDataAdd to start inserting HSZ/HAPP
  17684.   * pairs.  It then truncates the list with a 0 HSZ and returns the offset
  17685.   * to the terminator (ready to be called again to add more).
  17686.   *
  17687.   * returns 0L on error.
  17688.   */
  17689.  ULONG
  17690.  QueryAppNames(
  17691.  PAPPINFO pai,
  17692.  HDMGDATA hDataAdd,
  17693.  HSZ hszApp,
  17694.  ULONG offAdd)
  17695.  {
  17696.      USHORT chsz;
  17697.      PHSZ phsz, phszPile;
  17698.      PPILEB pBlock;
  17699.  
  17700.      AssertF(sizeof(HSZ) == sizeof(HAPP), "Type size conflict");
  17701.  
  17702.      SemEnter();
  17703.      if (chsz = (USHORT)FindPileItem(pai->pAppNamePile,
  17704.              hszApp ? CmpULONG : NULL, (PBYTE)&hszApp, FPI_COUNT)) {
  17705.          /*
  17706.           * allocate for additions.
  17707.           */
  17708.          if (!DdeAddData(hDataAdd, NULL,
  17709.                  (chsz + 1L) * (sizeof(HSZ) + sizeof(HDMGDATA)), offAdd)) {
  17710.              offAdd = 0L;
  17711.              GetCurrentAppInfo(FALSE)->LastError = DMGERR_MEMORY_ERROR;
  17712.              goto Exit;
  17713.          }
  17714.  
  17715.          phsz = DDES_PABDATA((PDDESTRUCT)hDataAdd) + offAdd;
  17716.          if (hszApp) {
  17717.              *phsz++ = hszApp;       /* only one per thread expected */
  17718.              *phsz++ = (HSZ)pai->hwndFrame;
  17719.          } else {
  17720.              pBlock = pai->pAppNamePile->pBlockFirst;
  17721.              while (pBlock) {
  17722.                  phszPile = (PHSZ)(pBlock + 1);
  17723.                  for (chsz = 0; chsz < pBlock->cItems; chsz++) {
  17724.                      *(phsz++) = *(phszPile++);
  17725.                      *(phsz++) = (HSZ)pai->hwndFrame;
  17726.                  }
  17727.                  pBlock = pBlock->next;
  17728.              }
  17729.          }
  17730.          *phsz = 0L;
  17731.          offAdd = phsz - DDES_PABDATA((PDDESTRUCT)hDataAdd);
  17732.      }
  17733.  Exit:
  17734.      SemLeave();
  17735.      return(offAdd);
  17736.  }
  17737.  
  17738.  
  17739.  
  17740.  DMGDDE.C
  17741.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGDDE.C
  17742.  
  17743.  /****************************** Module Header ******************************\
  17744.  * Module Name: DMGDDE.C
  17745.  *
  17746.  * This module contains functions used for interfacing with DDE structures
  17747.  * and such.
  17748.  *
  17749.  * Created:  12/23/88    sanfords
  17750.  *
  17751.  * Copyright (c) 1988, 1989  Microsoft Corporation
  17752.  \***************************************************************************/
  17753.  #include "ddemlp.h"
  17754.  
  17755.  /***************************** Private Function ****************************\
  17756.  * timeout()
  17757.  *
  17758.  * This routine creates a timer for hwndTimeout.  It then runs a modal loop
  17759.  * which will exit once the WM_TIMER message is received by hwndTimeout.
  17760.  * hwndTimeout can be any window that doesn't use timers itself with TID_TIMEO
  17761.  * or TID_ABORT since its window proc doesn't need to do
  17762.  * anything for this to work.  Only the client and server windows use these
  17763.  * so were cool.
  17764.  * Only one timeout window is allowed per thread.  This is checked by the
  17765.  * pai passed in.
  17766.  *
  17767.  * Returns fSuccess, ie TRUE if TID_TIMEOUT was received before TID_ABORT.
  17768.  *
  17769.  * PUBDOC START
  17770.  * Synchronous client transaction modal loops:
  17771.  *
  17772.  * During Synchronous transactions, a client application will enter a modal
  17773.  * loop while waiting for the server to respond to the request.  If an
  17774.  * application wishes to filter messages to the modal loop, it may do so
  17775.  * by setting a message filter tied to MSGF_DDE.  Applications should
  17776.  * be aware however that the DDE modal loop processes private messages
  17777.  * in the WM_USER range, WM_DDE messages, and WM_TIMER messages with timer IDs
  17778.  * using the TID_ constants defined in ddeml.h.
  17779.  * These messages must not be filtered by an application!!!
  17780.  *
  17781.  * PUBDOC END
  17782.  *
  17783.  * History:
  17784.  *   Created     sanfords    12/19/88
  17785.  \***************************************************************************/
  17786.  BOOL timeout(pai, ulTimeout, hwndTimeout)
  17787.  PAPPINFO pai;
  17788.  ULONG ulTimeout;
  17789.  HWND hwndTimeout;
  17790.  {
  17791.      QMSG qmsg;
  17792.  
  17793.      SemEnter();
  17794.      if (pai->hwndTimer) {
  17795.          pai->LastError = DMGERR_REENTRANCY;
  17796.          AssertF(FALSE, "Recursive timeout call");
  17797.          SemLeave();
  17798.          return(FALSE);
  17799.      }
  17800.      pai->hwndTimer = hwndTimeout;
  17801.      SemLeave();
  17802.  
  17803.      WinStartTimer(DMGHAB, hwndTimeout, TID_TIMEOUT, (USHORT)ulTimeout);
  17804.  
  17805.      WinGetMsg(DMGHAB, &qmsg, (HWND)NULL, 0, 0);
  17806.  
  17807.      /*
  17808.       * stay in modal loop until a timeout happens.
  17809.       */
  17810.      while (qmsg.hwnd != hwndTimeout ||
  17811.              qmsg.msg != WM_TIMER ||
  17812.              (LOUSHORT(qmsg.mp1) != TID_TIMEOUT &&
  17813.              LOUSHORT(qmsg.mp1) != TID_ABORT)) {
  17814.  
  17815.          if (!WinCallMsgFilter(DMGHAB, &qmsg, MSGF_DDE))
  17816.              WinDispatchMsg(DMGHAB, &qmsg);
  17817.  
  17818.          WinGetMsg(DMGHAB, &qmsg, (HWND)NULL, 0, 0);
  17819.      }
  17820.  
  17821.      WinStopTimer(DMGHAB, hwndTimeout, TID_TIMEOUT);
  17822.      SemEnter();
  17823.      pai->hwndTimer = 0;
  17824.      SemLeave();
  17825.      /*
  17826.       * post a callback check incase we blocked callbacks due to being
  17827.       * in a timeout.
  17828.       */
  17829.      WinPostMsg(pai->hwndDmg, UM_CHECKCBQ, (MPARAM)pai, 0L);
  17830.      return(LOUSHORT(qmsg.mp1) == TID_TIMEOUT);
  17831.  }
  17832.  
  17833.  
  17834.  /***************************** Private Function ****************************\
  17835.  *
  17836.  *  Based on pii, this sends an INITIATE message to either an exact
  17837.  *  target window (hwndSend), a target frame window (hwndFrame) or to all
  17838.  *  top level frames (both hwnds are NULL).  It fills in pci info as apropriat
  17839.  *  Note that pii->pCC must NOT be NULL and is assumed to be properly set.
  17840.  *
  17841.  *  Returns FALSE if SendDDEInit failed.
  17842.  *  On success pci->ci.xad.state is CONVST_CONNECTED.
  17843.  *
  17844.  * History:
  17845.  *   created 12/21/88        sanfords
  17846.  \***************************************************************************/
  17847.  BOOL ClientInitiate(hwnd, pii, pci)
  17848.  HWND hwnd;
  17849.  PINITINFO pii;
  17850.  PCLIENTINFO pci;
  17851.  {
  17852.      BOOL fRet = TRUE;
  17853.  
  17854.      if (pii->pCC->cb < sizeof(CONVCONTEXT))
  17855.          return(FALSE);
  17856.  
  17857.      SemEnter();
  17858.      /*
  17859.       * we need to set this info BEFORE we do the synchronous initiate
  17860.       * so the INITIATEACK msg is done correctly.
  17861.       */
  17862.      pci->ci.xad.state = CONVST_INIT1;
  17863.      pci->ci.xad.LastError = DMGERR_NO_ERROR;
  17864.      pci->ci.hszServerApp = pii->hszAppName;
  17865.      pci->ci.hszTopic = pii->hszTopic;
  17866.      pci->ci.cc.cb = sizeof(CONVCONTEXT);
  17867.      CopyBlock((PBYTE)&pii->pCC->fsContext, (PBYTE)&pci->ci.cc.fsContext,
  17868.          sizeof(CONVCONTEXT) - sizeof(USHORT));
  17869.      pci->ci.hwndFrame = pii->hwndFrame;
  17870.      SemLeave();
  17871.  
  17872.      fRet = SendDDEInit(hwnd,
  17873.              WinIsWindow(DMGHAB, pii->hwndSend) ? pii->hwndSend : pii->hwndFra
  17874.              pci);
  17875.      SemEnter();
  17876.      /*
  17877.       * If we failed to initiate directly with the server, try the frame.
  17878.       */
  17879.      if (!fRet && WinIsWindow(DMGHAB, pii->hwndSend) &&
  17880.              WinIsWindow(DMGHAB, pii->hwndFrame)) {
  17881.          SemLeave();
  17882.          fRet = SendDDEInit(hwnd, pii->hwndFrame, pci);
  17883.          if (fRet) {
  17884.              /*
  17885.               * OK, client is locked in so he wont go away on a terminate
  17886.               * from a random window. If the new server is not the same
  17887.               * window as the origonal, send it a terminate so it can
  17888.               * go away nicely.
  17889.               */
  17890.              if (pii->hwndSend != pci->ci.hwndPartner)
  17891.                  WinSendMsg(pii->hwndSend, WM_DDE_TERMINATE, 0L, 0L);
  17892.          }
  17893.          SemEnter();
  17894.  
  17895.      }
  17896.      if (!fRet)
  17897.          pci->ci.xad.state = CONVST_NULL;
  17898.      else {
  17899.          /*
  17900.           * successful initiate means we want to keep these around awhile.
  17901.           * removed at window closing time.
  17902.           */
  17903.          IncHszCount(pci->ci.hszServerApp);
  17904.          IncHszCount(pci->ci.hszTopic);
  17905.      }
  17906.      SemLeave();
  17907.      return(fRet);
  17908.  }
  17909.  
  17910.  
  17911.  
  17912.  /***************************** Private Function ****************************\
  17913.  * Allocates and sends a WM_DDE_INITIATE message to hwndTo.  Any failures
  17914.  * cause FALSE to be returned.  If hwndTo is NULL, performs equivalent of
  17915.  * WinDdeInitiate2().
  17916.  *
  17917.  * History:
  17918.  *   created     12/22/88        sanfords
  17919.  *   2/2/89  sanfords    added SEG_GETABLE during monitoring.
  17920.  \***************************************************************************/
  17921.  BOOL SendDDEInit(hwndFrom, hwndTo, pci)
  17922.  HWND hwndFrom;
  17923.  HWND hwndTo;
  17924.  PCLIENTINFO pci;
  17925.  {
  17926.      PID pidTo;
  17927.      TID tid;
  17928.      SEL sel;
  17929.      PDDEINIT pddeinit;
  17930.      HENUM henum;
  17931.      ULONG ul;
  17932.      USHORT cchApp, cchTopic;
  17933.      PSZ pszApp, pszTopic;
  17934.      BOOL fEnumerating;  /* set if extra acks are ok */
  17935.  
  17936.      SemCheckOut();
  17937.  
  17938.      if (hwndTo == NULL) {
  17939.          /*
  17940.           * Call on self for all top level frame windows until we are connecte
  17941.           * (if enumerating, do em all anyway.)
  17942.           */
  17943.          fEnumerating = WinQueryWindow(hwndFrom, QW_PARENT, FALSE) !=
  17944.                  pci->ci.pai->hwndDmg;
  17945.          if (henum = WinBeginEnumWindows(HWND_DESKTOP)) {
  17946.              while ((hwndTo = WinGetNextWindow(henum)) &&
  17947.                      (fEnumerating || pci->ci.xad.state == CONVST_INIT1)) {
  17948.                  if (hwndTo != pci->ci.pai->hwndFrame &&
  17949.                          (ul = (ULONG)WinSendMsg(hwndTo, WM_QUERYFRAMEINFO, 0L
  17950.                          (ul & FI_FRAME))
  17951.                      SendDDEInit(hwndFrom, hwndTo, pci);
  17952.              }
  17953.              WinEndEnumWindows(henum);
  17954.          }
  17955.          return(TRUE);
  17956.      }
  17957.  
  17958.      if (WinQueryWindowProcess(hwndTo, &pidTo, &tid) == NULL)
  17959.          return(FALSE);
  17960.  
  17961.      SemEnter();
  17962.      pszApp = pszFromHsz(pci->ci.hszServerApp, &cchApp);
  17963.      pszTopic = pszFromHsz(pci->ci.hszTopic, &cchTopic);
  17964.      if (DosAllocSeg(sizeof(DDEINIT) + sizeof(CONVCONTEXT) + cchApp + cchTopic
  17965.                  &sel, SEG_GIVEABLE) != 0) {
  17966.          SemLeave();
  17967.          return(FALSE);
  17968.      }
  17969.      pddeinit = MAKEP(sel, 0);
  17970.      pddeinit->cb = sizeof(DDEINIT);
  17971.      pddeinit->offConvContext = sizeof(DDEINIT);
  17972.      pddeinit->pszAppName = (PSZ)pddeinit + sizeof(DDEINIT) + sizeof(CONVCONTE
  17973.      pddeinit->pszTopic = pddeinit->pszAppName + cchApp;
  17974.      CopyBlock((PBYTE)&pci->ci.cc, (PBYTE)DDEI_PCONVCONTEXT(pddeinit), sizeof(
  17975.      CopyBlock((PBYTE)pszApp, (PBYTE)pddeinit->pszAppName, cchApp);
  17976.      CopyBlock((PBYTE)pszTopic, (PBYTE)pddeinit->pszTopic, cchTopic);
  17977.      FarFreeMem(hheapDmg, pszApp, cchApp);
  17978.      FarFreeMem(hheapDmg, pszTopic, cchTopic);
  17979.      SemLeave();
  17980.  
  17981.      if (DosGiveSeg(sel, pidTo, &sel) != 0) {
  17982.          DosFreeSeg(sel);
  17983.          return(FALSE);
  17984.      }
  17985.  
  17986.      WinSendMsg(hwndTo, WM_DDE_INITIATE, (MPARAM)hwndFrom, pddeinit);
  17987.      if (pidTo != pci->ci.pai->pid)
  17988.          DosFreeSeg(sel);
  17989.      return(TRUE);
  17990.  }
  17991.  
  17992.  
  17993.  
  17994.  /***************************** Private Function ****************************\
  17995.  *
  17996.  *  Alocates and fills in a MYDDES. if pai == 0, the MYDDES is considered
  17997.  * unowned.
  17998.  *
  17999.  * History:  created     1/4/89  sanfords
  18000.  * 10/18/89  sanfords Added hack so that if usFmt==DDEFMT_TEXT and hszItem==0L
  18001.  *                    the data and item strings are one.
  18002.  *                    (This allows for excel EXEC compatibility)
  18003.  *   2/2/89  sanfords Added GETABLE during monitoring.
  18004.  *  6/13/90  sanfords Altered to not expand hszItem at this point.
  18005.  \***************************************************************************/
  18006.  PDDESTRUCT AllocDDESel(fsStatus, usFmt, hszItem, cbData, pai)
  18007.  USHORT fsStatus;
  18008.  USHORT usFmt;
  18009.  HSZ hszItem;
  18010.  ULONG cbData;
  18011.  PAPPINFO pai;
  18012.  {
  18013.      PMYDDES pmyddes = NULL;
  18014.      ULONG cbTotal;
  18015.      ULONG cchItem;
  18016.      SEL sel;
  18017.  
  18018.      SemEnter();
  18019.      cchItem = DdeGetHszString(hszItem, NULL, 0L) + 1L;
  18020.  
  18021.      /*
  18022.       * This hack makes execs conform to EXCELs way.
  18023.       */
  18024.      if (!hszItem && usFmt == DDEFMT_TEXT)
  18025.          cchItem = 0L;
  18026.  
  18027.      cbTotal = sizeof(MYDDES) + cchItem + cbData + 1;
  18028.      if (cbTotal <= 0xFFFF) {
  18029.          if (DosAllocSeg((USHORT)cbTotal, &sel, SEG_GIVEABLE) != 0)
  18030.              goto allocDdeExit;
  18031.      } else {
  18032.          if (DosAllocHuge((USHORT)(cbTotal >> 16), (USHORT)cbTotal, &sel,
  18033.                  0, SEG_GIVEABLE) != 0)
  18034.              goto allocDdeExit;
  18035.      }
  18036.  
  18037.      pmyddes = MAKEP(sel, 0);
  18038.      pmyddes->cbData = cbData;
  18039.      pmyddes->fsStatus = fsStatus;
  18040.      pmyddes->usFormat = usFmt;
  18041.      pmyddes->offszItemName = sizeof(MYDDES);
  18042.      pmyddes->offabData = sizeof(MYDDES) + (USHORT)cchItem;
  18043.      pmyddes->ulRes1 = 0L;
  18044.      pmyddes->magic = MYDDESMAGIC;
  18045.      pmyddes->hszItem = hszItem;
  18046.      pmyddes->pai = pai;
  18047.      pmyddes->fs = 0;
  18048.      *DDES_PABDATA((PDDESTRUCT)pmyddes) = '\0'; /* in case data is never place
  18049.      *DDES_PSZITEMNAME((PDDESTRUCT)pmyddes) = '\0';  /* we expand this at post
  18050.  
  18051.  allocDdeExit:
  18052.      SemLeave();
  18053.      return((PDDESTRUCT)pmyddes);
  18054.  }
  18055.  
  18056.  
  18057.  
  18058.  
  18059.  /***************************** Private Function ****************************\
  18060.  * This routine returns the hwnd of a newly created and connected DDE
  18061.  * client or NULL if failure.
  18062.  *
  18063.  * History:  created     1/6/89  sanfords
  18064.  \***************************************************************************/
  18065.  HCONV GetDDEClientWindow(hConvList, hwndFrame, hwndSend, hszApp, hszTopic, pC
  18066.  HCONVLIST hConvList;
  18067.  HWND hwndFrame;
  18068.  HWND hwndSend;
  18069.  HSZ hszApp;
  18070.  HSZ hszTopic;
  18071.  PCONVCONTEXT pCC;
  18072.  {
  18073.      HCONV hConv;
  18074.      INITINFO ii;
  18075.      CONVCONTEXT cc;
  18076.  
  18077.      SemCheckOut();
  18078.  
  18079.      hConv = WinCreateWindow(hConvList, SZCLIENTCLASS, "", 0L,
  18080.              0, 0, 0, 0, (HWND)NULL, HWND_TOP, WID_CLIENT, 0L, 0L);
  18081.  
  18082.      if (hConv == NULL)
  18083.          return(NULL);
  18084.  
  18085.      ii.hszTopic = hszTopic;
  18086.      ii.hszAppName = hszApp;
  18087.      ii.hwndSend = hwndSend;
  18088.      ii.hwndFrame = hwndFrame;
  18089.      if (pCC == NULL) {
  18090.          pCC = &cc;
  18091.          cc.cb = sizeof(CONVCONTEXT);
  18092.          cc.fsContext = 0;
  18093.          /*##LATER - may want to use process codepage instead */
  18094.          cc.usCodepage = syscc.codepage;
  18095.          cc.idCountry = syscc.country;
  18096.      }
  18097.      if (pCC->usCodepage == 0)
  18098.          pCC->usCodepage = syscc.codepage;
  18099.      if (pCC->idCountry == 0)
  18100.          pCC->idCountry = syscc.country;
  18101.  
  18102.      ii.pCC = pCC;
  18103.      WinSendMsg(hConv, UMCL_INITIATE, (MPARAM)&ii, 0L);
  18104.  
  18105.      if (!((USHORT)WinSendMsg(hConv, UM_QUERY, (MPARAM)Q_STATUS, 0L) &
  18106.              ST_CONNECTED)) {
  18107.          WinDestroyWindow(hConv);
  18108.          return(NULL);
  18109.      }
  18110.      return(hConv);
  18111.  }
  18112.  
  18113.  
  18114.  
  18115.  /***************************** Private Function ****************************\
  18116.  * This routine institutes a callback directly if psi->fEnableCB is set
  18117.  * and calls QReply to complete the transaction,
  18118.  * otherwise it places the data into the queue for processing.
  18119.  *
  18120.  * Since hDmgData may be freed by the app at any time once the callback is
  18121.  * issued, we cannot depend on it being there for QReply.  Therefore we
  18122.  * save all the pertinant data in the queue along with it.
  18123.  *
  18124.  * Returns fSuccess.
  18125.  *
  18126.  * History:
  18127.  *   Created     9/12/89    Sanfords
  18128.  \***************************************************************************/
  18129.  BOOL MakeCallback(pai, hConv, hszTopic, hszItem, usFmt, usType, hDmgData,
  18130.      msg, fsStatus, hConvClient)
  18131.  PAPPINFO pai;
  18132.  HCONV hConv;
  18133.  HSZ hszTopic;
  18134.  HSZ hszItem;
  18135.  USHORT usFmt;
  18136.  USHORT usType;
  18137.  HDMGDATA hDmgData;
  18138.  USHORT msg;
  18139.  USHORT fsStatus;
  18140.  HCONV hConvClient;
  18141.  {
  18142.      PCBLI pcbli;
  18143.  
  18144.      SemEnter();
  18145.  
  18146.      if (!(pcbli = (PCBLI)NewLstItem(pai->plstCB, ILST_LAST))) {
  18147.          pai->LastError = DMGERR_MEMORY_ERROR;
  18148.          SemLeave();
  18149.          return(FALSE);
  18150.      }
  18151.      pcbli->hConv = hConv;
  18152.      pcbli->hszTopic = hszTopic;
  18153.      pcbli->hszItem = hszItem;
  18154.      pcbli->usFmt = usFmt;
  18155.      pcbli->usType = usType;
  18156.      pcbli->hDmgData = hDmgData;
  18157.      pcbli->msg = msg;
  18158.      pcbli->fsStatus = fsStatus;
  18159.      pcbli->hConvPartner = hConvClient;
  18160.  
  18161.      if (pai->fEnableCB && !pai->hwndTimer) {
  18162.          SemLeave();
  18163.          WinPostMsg(pai->hwndDmg, UM_CHECKCBQ, (MPARAM)pai, 0L);
  18164.      } else
  18165.          SemLeave();
  18166.  
  18167.      return(TRUE);
  18168.  }
  18169.  
  18170.  
  18171.  
  18172.  /*************************************************************************\
  18173.  * Attempts to post a DDE message to hwndTo.  Properly frees up pmyddes
  18174.  * if afCmd has MDPM_FREEHDATA set.  We do not add pmyddes to the target
  18175.  * thread list since we assume that will be done at the receiving end
  18176.  * if necessary.
  18177.  *
  18178.  * Returns fSuccess.
  18179.  *
  18180.  * 6/12/90 sanfords  Created
  18181.  * 6/13/90 sanfords  Made it convert hszItem to a string at this point
  18182.  *                   only if hwndTo is not a local guy.
  18183.  \*************************************************************************/
  18184.  BOOL MyDdePostMsg(
  18185.  HWND hwndTo,
  18186.  HWND hwndFrom,
  18187.  USHORT msg,
  18188.  PMYDDES pmyddes,
  18189.  PAPPINFO paiFrom,
  18190.  USHORT afCmd)
  18191.  {
  18192.      PID pid;
  18193.      TID tid;
  18194.      SEL selR;
  18195.      BOOL fRet;
  18196.      PFNWP pfnwpTo;
  18197.  
  18198.      if (!WinQueryWindowProcess(hwndTo, &pid, &tid))
  18199.          return FALSE;
  18200.  
  18201.      pfnwpTo = (PFNWP)WinQueryWindowPtr(hwndTo, QWP_PFNWP);
  18202.      if (cMonitor || (pfnwpTo != ServerWndProc && pfnwpTo != ClientWndProc)) {
  18203.          /*
  18204.           * its not local - expand hszItem if necessary - always
  18205.           * expand if a monitor is installed.
  18206.           */
  18207.          if (CheckSel(SELECTOROF(pmyddes)) >= sizeof(MYDDES) &&
  18208.                  pmyddes->magic == MYDDESMAGIC &&
  18209.                  pmyddes->hszItem &&
  18210.                  !(pmyddes->fs & HDATA_PSZITEMSET)) {
  18211.              pmyddes->fs |= HDATA_PSZITEMSET;
  18212.              QueryHszName(pmyddes->hszItem, DDES_PSZITEMNAME(pmyddes),
  18213.                      pmyddes->offabData - pmyddes->offszItemName);
  18214.          }
  18215.      }
  18216.      /*
  18217.       * Don't try to share seg with ourselves.
  18218.       */
  18219.      if (paiFrom->pid != pid) {
  18220.          selR = SELECTOROF(pmyddes);
  18221.          if (DosGiveSeg(SELECTOROF(pmyddes), pid, &selR))
  18222.              return FALSE;
  18223.          if (afCmd & MDPM_FREEHDATA)
  18224.              FreeData(pmyddes, paiFrom);
  18225.      } else {
  18226.          /*
  18227.           * just remove hData from our thread list
  18228.           */
  18229.          if (afCmd & MDPM_FREEHDATA && !(pmyddes->fs & HDATA_APPOWNED))
  18230.              FindPileItem(paiFrom->pHDataPile, CmpULONG, (PBYTE)&pmyddes,
  18231.                      FPI_DELETE);
  18232.      }
  18233.      fRet = (BOOL)WinPostMsg(hwndTo, msg, (MPARAM)hwndFrom, (MPARAM)pmyddes);
  18234.      if (!fRet) {
  18235.          /*
  18236.           * make sure this is freed if it is supposed to be - this covers
  18237.           * the case where the target is of the same process and only
  18238.           * these two threads are registered.
  18239.           */
  18240.  
  18241.          tid = paiFrom->tid;
  18242.          do {
  18243.              if (FindPileItem(paiFrom->pHDataPile, CmpULONG, (PBYTE)&pmyddes,
  18244.                      FPI_COUNT))
  18245.                  return(FALSE);  /* there is another thread that has this */
  18246.              paiFrom = paiFrom->nextThread;
  18247.          } while (paiFrom->tid != tid);
  18248.          DosFreeSeg(SELECTOROF(pmyddes));
  18249.      }
  18250.      return(fRet);
  18251.  }
  18252.  
  18253.  
  18254.  DMGHSZ.C
  18255.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGHSZ.C
  18256.  
  18257.  /****************************** Module Header ******************************\
  18258.  * Module Name: DMGLATOM.C
  18259.  *
  18260.  * This module contains functions used for HSZ control.
  18261.  *
  18262.  * Created:  8/2/88    sanfords
  18263.  * Added case preservation/insensitive   1/22/90       Sanfords
  18264.  * 6/12/90 sanfords  Fixed HSZ local string allocation size errors.
  18265.  *                   Added latom validation checks
  18266.  *
  18267.  * Copyright (c) 1988, 1989  Microsoft Corporation
  18268.  \***************************************************************************/
  18269.  #include "ddemlp.h"
  18270.  
  18271.  
  18272.  /*
  18273.   * since the top 12 bits of any latom is always 0 (unless we have > 16
  18274.   * atom tables!) we can encode any ulong into only 5 bytes.
  18275.   */
  18276.  #define ENCODEBYTES         5
  18277.  #define MAX_LATOMSTRSIZE    255 - ENCODEBYTES - 2
  18278.  char szT[MAX_LATOMSTRSIZE + 1 + ENCODEBYTES];  /* used for HSZ expansion */
  18279.  
  18280.  extern BOOL APIENTRY WinSetAtomTableOwner( HATOMTBL, PID );
  18281.  
  18282.  
  18283.  /*********************** LATOM management functions *************************
  18284.  * An HSZ is a long atom which holds an encoded reference to two other long
  18285.  * atoms.  One long atom is for the actual string, the other is for its
  18286.  * uppercase version.  Two HSZs are ranked by their uppercase latoms.
  18287.  * This makes HSZs case insensitive, case preserving.  An latom
  18288.  * is an atom with an atom table index tacked onto the HIUSHORT part of
  18289.  * of the latom.  Strings too long for the atom manager are split up and
  18290.  * each piece is prepended with a coded string that represents the
  18291.  * LATOM of the rest of the string.  LATOM strings thus may be of any length.
  18292.  * (up to 64K in this version)
  18293.  *
  18294.  * History:
  18295.  *   Created     9/12/89    Sanfords
  18296.  \***************************************************************************/
  18297.  
  18298.  /***************************** Private Function ****************************\
  18299.  * Allocates space in the DDE manager heap for a string queried from the DDE
  18300.  * manager latomtable.  The case sensitive string is returned.
  18301.  *
  18302.  * This function should be serialized.  Memory allocation or latom table failu
  18303.  * results in a 0 return value.
  18304.  *
  18305.  * 0 latoms result in a NULL terminated empty string.
  18306.  *
  18307.  * Note that *pcch is set to the length of the string INCLUDING the null
  18308.  * terminator.  This way a wild string has a cch=1.
  18309.  *
  18310.  * History:
  18311.  *   created     12/22/88        sanfords
  18312.  *   11/10/89    sanfords        modified to return '\0' on invalid atom.
  18313.  \***************************************************************************/
  18314.  PSZ pszFromHsz(hsz, pcch)
  18315.  HSZ hsz;
  18316.  USHORT FAR *pcch;
  18317.  {
  18318.      PSZ psz;
  18319.      LATOM latom;
  18320.      char sz[ENCODEBYTES + 1];
  18321.      register USHORT cch;
  18322.  
  18323.      SemCheckIn();
  18324.  
  18325.      if (hsz == 0)
  18326.          cch = 1;
  18327.      else {
  18328.          QuerylatomName((LATOM)hsz, sz, ENCODEBYTES + 1);
  18329.          latom = Decode(sz);     /* take origonal case version */
  18330.          cch = QuerylatomLength(latom) + 1;
  18331.      }
  18332.  
  18333.      psz = (PSZ)FarAllocMem(hheapDmg, cch);
  18334.      if (psz == 0) {
  18335.          *pcch = '\000';
  18336.          return(0);
  18337.      }
  18338.  
  18339.      if (hsz == 0) {
  18340.          *pcch = 1;
  18341.          *psz = '\0';
  18342.      } else {
  18343.          *pcch = cch;
  18344.          if (QuerylatomName(latom, psz, cch) == 0) {
  18345.              AssertF(FALSE, "pszFromHsz - bad latom");
  18346.              *psz = '\0';        /* invalid case - never expected */
  18347.          }
  18348.      }
  18349.      return(psz);
  18350.  }
  18351.  
  18352.  
  18353.  /***************************** Private Function ****************************\
  18354.  * HSZ GetHsz(psz, cc, cp, fAdd)
  18355.  * PSZ psz;
  18356.  * USHORT cc;
  18357.  * USHORT cp;
  18358.  * BOOL fAdd;
  18359.  *
  18360.  * The goal of this routine is to convert a psz to an hsz.  This uses the
  18361.  * atom manager for its dirty work.  This call has the side effect of
  18362.  * incrementing the use count for the hsz returned and its associated latoms
  18363.  * if fAdd is set.
  18364.  *
  18365.  * if fAdd is FALSE, NULL is returned if the hsz doesn't exist.
  18366.  *
  18367.  * History:
  18368.  *   created     12/23/88    sanfords
  18369.  \***************************************************************************/
  18370.  HSZ GetHsz(psz, cc, cp, fAdd)
  18371.  PSZ psz;
  18372.  USHORT cc;
  18373.  USHORT cp;
  18374.  BOOL fAdd;
  18375.  {
  18376.      LATOM latom1, latom2;
  18377.      USHORT cb;
  18378.      PSZ pszT;
  18379.      BOOL fNew = FALSE;
  18380.      HSZ hsz;
  18381.  
  18382.      /*
  18383.       * NULL or 0 length pszs are considered wild HSZs.
  18384.       */
  18385.      if (psz == NULL || *psz == '\0')
  18386.          return(0L);
  18387.  
  18388.      SemEnter();
  18389.  
  18390.      if (!(latom1 = FindAddlatom(psz, fAdd))) {
  18391.          AssertF(!fAdd, "GetHsz - Atom Add failed");
  18392.          SemLeave();
  18393.          return(0L);
  18394.      }
  18395.  
  18396.      cb = lstrlen(psz) + 1;
  18397.  
  18398.      if (!(pszT = FarAllocMem(hheapDmg, max(cb, ENCODEBYTES * 2 + 1)))) {
  18399.          SemLeave();
  18400.          return(0L);
  18401.      }
  18402.  
  18403.      CopyBlock((PBYTE)psz, (PBYTE)pszT, cb);
  18404.      WinUpper(DMGHAB, cp ? cp : syscc.codepage, cc ? cc : syscc.country, pszT)
  18405.      latom2 = FindAddlatom(pszT, fAdd);
  18406.  
  18407.      if (!latom2) {
  18408.          AssertF(!fAdd, "GetHsz - Atom Add(2) failed");
  18409.          hsz = 0;
  18410.      } else {
  18411.          *Encode(latom2, Encode(latom1, pszT)) = '\000';
  18412.          hsz = (HSZ)FindAddlatom(pszT, fAdd);
  18413.      }
  18414.      FarFreeMem(hheapDmg, pszT, max(cb, ENCODEBYTES * 2 + 1));
  18415.      SemLeave();
  18416.      return(hsz);
  18417.  }
  18418.  
  18419.  
  18420.  
  18421.  /*
  18422.   * Note that all three associated latoms are freed.
  18423.   */
  18424.  BOOL FreeHsz(hsz)
  18425.  HSZ hsz;
  18426.  {
  18427.      char sz[ENCODEBYTES * 2 + 1];
  18428.  
  18429.      SemEnter();
  18430.      if (hsz && QuerylatomName((LATOM)hsz, sz, ENCODEBYTES * 2 + 1)) {
  18431.          Freelatom(Decode((PBYTE)sz));
  18432.          Freelatom(Decode((PBYTE)&sz[ENCODEBYTES]));
  18433.          Freelatom((LATOM)hsz);
  18434.      }
  18435.      SemLeave();
  18436.      return(TRUE);
  18437.  }
  18438.  
  18439.  
  18440.  
  18441.  /*
  18442.   * Note that all three associated latoms are incremented.
  18443.   */
  18444.  BOOL IncHszCount(hsz)
  18445.  HSZ hsz;
  18446.  {
  18447.      char sz[ENCODEBYTES * 2 + 1];
  18448.      register BOOL fRet;
  18449.  
  18450.      if (hsz == 0)
  18451.          return(TRUE);
  18452.  
  18453.      SemEnter();
  18454.  
  18455.      QuerylatomName((LATOM)hsz, sz, ENCODEBYTES * 2 + 1);
  18456.      fRet = InclatomCount(Decode((PBYTE)sz)) &&
  18457.                  InclatomCount(Decode((PBYTE)&sz[ENCODEBYTES])) &&
  18458.                  InclatomCount((LATOM)hsz);
  18459.      SemLeave();
  18460.      return(fRet);
  18461.  }
  18462.  
  18463.  
  18464.  
  18465.  /***************************** Private Function ****************************\
  18466.  * This routine adds an atom table and returns its handle.  Returns fSuccess.
  18467.  *
  18468.  * Effects cAtbls, aAtbls, iAtblCurrent;
  18469.  *
  18470.  * History:
  18471.  *   Created     9/12/89    Sanfords
  18472.  \***************************************************************************/
  18473.  BOOL AddAtomTable(fInit)
  18474.  BOOL fInit;
  18475.  {
  18476.      PHATOMTBL pat;
  18477.  
  18478.      SemEnter();
  18479.  
  18480.      if (!(pat = (PHATOMTBL)FarAllocMem(hheapDmg,
  18481.              sizeof(HATOMTBL) * (cAtbls + 1)))) {
  18482.          SemLeave();
  18483.          return(FALSE);
  18484.      }
  18485.  
  18486.      if (!fInit) {
  18487.          CopyBlock((PBYTE)aAtbls, (PBYTE)pat, sizeof(HATOMTBL) * cAtbls);
  18488.          FarFreeMem(hheapDmg, aAtbls, sizeof(HATOMTBL) * cAtbls);
  18489.      }
  18490.  
  18491.      aAtbls = pat;
  18492.  
  18493.      if (!(aAtbls[cAtbls] = WinCreateAtomTable(0, 0)))
  18494.          return(FALSE);
  18495.      /*
  18496.       * Share our atom tables with all processes...
  18497.       */
  18498.      if (!WinSetAtomTableOwner(aAtbls[cAtbls], NULL)) {
  18499.          AssertF(FALSE, "AddAtomTable - WinSetAtomTable failed");
  18500.          return(FALSE);
  18501.      }
  18502.      iAtblCurrent = cAtbls++;
  18503.      SemLeave();
  18504.      return(TRUE);
  18505.  }
  18506.  
  18507.  
  18508.  
  18509.  USHORT QueryHszLength(hsz)
  18510.  HSZ hsz;
  18511.  {
  18512.      char sz[ENCODEBYTES + 1];
  18513.      USHORT us;
  18514.  
  18515.      if (!hsz)
  18516.          return(0);
  18517.      SemEnter();
  18518.      QuerylatomName((LATOM)hsz, sz, ENCODEBYTES + 1);
  18519.      us = QuerylatomLength(Decode(sz));
  18520.      SemLeave();
  18521.      return(us);
  18522.  }
  18523.  
  18524.  
  18525.  
  18526.  USHORT QueryHszName(hsz, psz, cchMax)
  18527.  HSZ hsz;
  18528.  PSZ psz;
  18529.  USHORT cchMax;
  18530.  {
  18531.      char sz[ENCODEBYTES + 1];
  18532.      register USHORT usRet;
  18533.  
  18534.      if (hsz == 0) {
  18535.          if (psz)
  18536.              *psz = '\000';
  18537.          return(1);
  18538.      } else {
  18539.          usRet = 0;
  18540.          SemEnter();
  18541.          if (QuerylatomName((LATOM)hsz, sz, ENCODEBYTES + 1))
  18542.              usRet = QuerylatomName(Decode(sz), psz, cchMax);
  18543.          SemLeave();
  18544.          return(usRet);
  18545.      }
  18546.  }
  18547.  
  18548.  
  18549.  
  18550.  /*
  18551.   * returns 0 if ==, -1 if hsz1 < hsz2, 1 if hsz1 > hsz2, 2 on error
  18552.   */
  18553.  SHORT CmpHsz(hsz1, hsz2)
  18554.  HSZ hsz1, hsz2;
  18555.  {
  18556.      char sz[ENCODEBYTES * 2 + 1];
  18557.      LATOM latom;
  18558.      SHORT usRet;
  18559.  
  18560.      if (hsz1 == hsz2)
  18561.          return(0);
  18562.      if (!hsz1)
  18563.          return(-1);
  18564.      if (!hsz2)
  18565.          return(1);
  18566.  
  18567.      usRet = 2;
  18568.      SemEnter();
  18569.      if (QuerylatomName((LATOM)hsz1, sz, ENCODEBYTES * 2 + 1)) {
  18570.          latom = Decode(&sz[ENCODEBYTES]);   /* use UPPERCASE form for compari
  18571.          if (QuerylatomName((LATOM)hsz2, sz, ENCODEBYTES * 2 + 1)) {
  18572.              latom = latom - Decode(&sz[ENCODEBYTES]);
  18573.              usRet = latom == 0 ? 0 : (latom > 0 ? 1 : -1);
  18574.          }
  18575.      }
  18576.      SemLeave();
  18577.      return(usRet);
  18578.  }
  18579.  
  18580.  
  18581.  
  18582.  
  18583.  /***************************** Private Function ****************************\
  18584.  * Returns the length of the latom given without NULL terminator.
  18585.  * Wild LATOMs have a length of 0.
  18586.  *
  18587.  * History:
  18588.  *   Created     9/12/89    Sanfords
  18589.  \***************************************************************************/
  18590.  USHORT QuerylatomLength(latom)
  18591.  LATOM latom;
  18592.  {
  18593.      USHORT cb;
  18594.      USHORT cbT = 0;
  18595.      BYTE ab[ENCODEBYTES + 1];
  18596.  
  18597.      AssertF(HIUSHORT(latom) < cAtbls, "Invalid latom");
  18598.      if (latom == 0)
  18599.          return(0);
  18600.      SemCheckIn();
  18601.      while (TRUE) {
  18602.          if (!(cb = WinQueryAtomLength(aAtbls[HIUSHORT(latom)],
  18603.                  LOUSHORT(latom)))) {
  18604.              AssertF(cbT == 0, "QuerylatomLength - failed on continued latom")
  18605.              return(0);
  18606.          }
  18607.  
  18608.          cbT += cb;
  18609.  
  18610.          if (cb <= MAX_LATOMSTRSIZE) {
  18611.              return(cbT);
  18612.          }
  18613.  
  18614.          /*
  18615.           * it MUST be a huge latom.
  18616.           */
  18617.          if (!(WinQueryAtomName(aAtbls[HIUSHORT(latom)], LOUSHORT(latom),
  18618.                  (PSZ)ab, ENCODEBYTES + 1))) {
  18619.              AssertF(FALSE, "QuerylatomLength - Length but no name");
  18620.              return(0);
  18621.          }
  18622.  
  18623.          latom = Decode(ab);
  18624.          cbT -= ENCODEBYTES;
  18625.      }
  18626.  }
  18627.  
  18628.  
  18629.  
  18630.  USHORT QuerylatomName(latom, psz, cchMax)
  18631.  LATOM latom;
  18632.  PSZ psz;
  18633.  USHORT cchMax;
  18634.  {
  18635.      USHORT cb;
  18636.      extern char szT[];
  18637.  
  18638.      if (HIUSHORT(latom) >= cAtbls) {
  18639.          AssertF(FALSE, "Invalid latom");
  18640.          psz[0] = '\0';
  18641.          return(0);
  18642.      }
  18643.  
  18644.      AssertF(latom != 0, "QuerylatomName - 0 latom");
  18645.      SemCheckIn();
  18646.      cb = WinQueryAtomLength(aAtbls[HIUSHORT(latom)], LOUSHORT(latom));
  18647.      if (cb > MAX_LATOMSTRSIZE) {
  18648.          if (!WinQueryAtomName(aAtbls[HIUSHORT(latom)], LOUSHORT(latom), szT,
  18649.                  MAX_LATOMSTRSIZE + ENCODEBYTES + 1)) {
  18650.              AssertF(FALSE, "QuerylatomName - length but no name");
  18651.              return(0);
  18652.          }
  18653.          CopyBlock(szT + ENCODEBYTES, psz, min(MAX_LATOMSTRSIZE, cchMax));
  18654.          latom = Decode((PBYTE)szT);
  18655.          cb = MAX_LATOMSTRSIZE + QuerylatomName(latom, psz + MAX_LATOMSTRSIZE,
  18656.                  cchMax > MAX_LATOMSTRSIZE ? cchMax - MAX_LATOMSTRSIZE : 0);
  18657.  
  18658.      } else {
  18659.          WinQueryAtomName(aAtbls[HIUSHORT(latom)], LOUSHORT(latom), psz, cchMa
  18660.      }
  18661.      psz[cchMax - 1] = '\0';     /* add NULL terminator */
  18662.      return(min(cb, cchMax - 1));
  18663.  }
  18664.  
  18665.  
  18666.  
  18667.  /***************************** Private Function ****************************\
  18668.  * This uses globals szT, aAtbls, cAtbls, and iAtblCurrent to add or
  18669.  * find the latom for psz depending on fAdd.
  18670.  *
  18671.  * History:
  18672.  *   Created     9/12/89    Sanfords
  18673.  \***************************************************************************/
  18674.  LATOM FindAddlatom(psz, fAdd)
  18675.  PSZ psz;
  18676.  BOOL fAdd;
  18677.  {
  18678.      LATOM latom;
  18679.  
  18680.      AssertF(psz != NULL, "FindAddlatom - NULL psz");
  18681.      AssertF(*psz != '\0', "FindAddlatom - NULL psz string");
  18682.      SemCheckIn();
  18683.      if (lstrlen(psz) > MAX_LATOMSTRSIZE) {
  18684.          latom = FindAddlatom(psz + MAX_LATOMSTRSIZE, fAdd);
  18685.          CopyBlock((PBYTE)psz, Encode((ULONG)latom, szT),
  18686.                  (ULONG)MAX_LATOMSTRSIZE - ENCODEBYTES + 1);
  18687.          szT[MAX_LATOMSTRSIZE + ENCODEBYTES] = '\0';
  18688.          latom = FindAddlatomHelper(szT, fAdd);
  18689.          return(latom);
  18690.      } else {
  18691.          return(FindAddlatomHelper(psz, fAdd));
  18692.      }
  18693.  }
  18694.  
  18695.  
  18696.  
  18697.  
  18698.  LATOM FindAddlatomHelper(psz, fAdd)
  18699.  PSZ psz;
  18700.  BOOL fAdd;
  18701.  {
  18702.      int i;
  18703.      ATOM atom;
  18704.      ATOM (APIENTRY *lpfn)(HATOMTBL, PSZ);
  18705.  
  18706.      SemCheckIn();
  18707.      if (fAdd) {
  18708.          AssertF(++cAtoms, "Possible atom count overflow");
  18709.          lpfn = WinAddAtom;
  18710.      } else
  18711.          lpfn = WinFindAtom;
  18712.  
  18713.      if (!(atom = (*lpfn)(aAtbls[i = iAtblCurrent], psz))) {
  18714.          /*
  18715.           * Must be full/not found, try all the existing tables
  18716.           */
  18717.          for (i = 0; i < cAtbls; i++) {
  18718.              if (i != iAtblCurrent) {
  18719.                  if (atom = (*lpfn)(aAtbls[i], psz)) {
  18720.                      if (fAdd)
  18721.                          iAtblCurrent = i;
  18722.                      break;
  18723.                  }
  18724.              }
  18725.          }
  18726.  
  18727.          if (!atom) {
  18728.              if (fAdd) {
  18729.                  /*
  18730.                   * they're all full, make another table.
  18731.                   */
  18732.                  if (!AddAtomTable(FALSE)) {
  18733.                      return(0L);
  18734.                  }
  18735.                  if (!(atom = (*lpfn)(aAtbls[iAtblCurrent], psz))) {
  18736.                      return(0L);
  18737.                  }
  18738.              } else {
  18739.                  return(0L);
  18740.              }
  18741.          }
  18742.      }
  18743.      return((LATOM)MAKEP(i, atom));
  18744.  }
  18745.  
  18746.  
  18747.  
  18748.  
  18749.  
  18750.  BOOL InclatomCount(latom)
  18751.  LATOM latom;
  18752.  {
  18753.      AssertF(HIUSHORT(latom) < cAtbls, "Invalid latom");
  18754.      AssertF(latom != 0, "InclatomCount - 0 latom");
  18755.      SemCheckIn();
  18756.      AssertF(++cAtoms, "Possible atom count overflow");
  18757.      return(WinAddAtom(aAtbls[HIUSHORT(latom)], MAKEP(0XFFFF, LOUSHORT(latom))
  18758.  }
  18759.  
  18760.  
  18761.  
  18762.  BOOL Freelatom(latom)
  18763.  LATOM latom;
  18764.  {
  18765.      AssertF(HIUSHORT(latom) < cAtbls, "Invalid latom");
  18766.      AssertF(latom != 0, "Freelatom - 0 latom");
  18767.      AssertF(WinQueryAtomUsage(aAtbls[HIUSHORT(latom)], LOUSHORT(latom)),
  18768.              "Freelatom - Freeing Non-existing atom");
  18769.      SemCheckIn();
  18770.  
  18771.      if (WinDeleteAtom(aAtbls[HIUSHORT(latom)], LOUSHORT(latom))) {
  18772.          AssertF(FALSE, "Freelatom - WinDeleteAtom failed");
  18773.          return(FALSE);
  18774.      }
  18775.      AssertF(--cAtoms >= 0, "Freelatom - negative atom count");
  18776.      return(TRUE);
  18777.  }
  18778.  
  18779.  
  18780.  
  18781.  
  18782.  #ifdef DEBUG
  18783.  BASEVAL '0'     /* more readable for debugging */
  18784.  #else
  18785.  BASEVAL 1       /* less likely to conflict with a string */
  18786.  #endif
  18787.  
  18788.  /***************************** Private Function ****************************\
  18789.  * Converts an latom into a ENCODEBYTES character string apropriate for
  18790.  * atomization. (NULL terminator must be added)
  18791.  *
  18792.  * History:
  18793.  *   Created     9/12/89    Sanfords
  18794.  \***************************************************************************/
  18795.  PBYTE Encode(latom, pb)
  18796.  ULONG latom;
  18797.  PBYTE pb;
  18798.  {
  18799.      int i;
  18800.  
  18801.  
  18802.      AssertF(HIUSHORT(latom) < cAtbls, "Invalid latom");
  18803.      for (i = 0; i < ENCODEBYTES; i++) {
  18804.          *pb++ = ((BYTE)latom & 0x0F) + BASEVAL;
  18805.          latom >>= 4;
  18806.      }
  18807.      return(pb);
  18808.  }
  18809.  
  18810.  
  18811.  
  18812.  /***************************** Private Function ****************************\
  18813.  * This takes a pointer to a buffer of 8 bytes which is a coded LATOM and
  18814.  * returns the LATOM.
  18815.  *
  18816.  * History:
  18817.  *   Created     9/12/89    Sanfords
  18818.  \***************************************************************************/
  18819.  LATOM Decode(pb)
  18820.  PBYTE pb;
  18821.  {
  18822.      ULONG ul = 0;
  18823.      int i;
  18824.  
  18825.      for (i = ENCODEBYTES - 1; i >= 0; i--) {
  18826.          ul <<= 4;
  18827.          ul += (ULONG)(pb[i] - BASEVAL);
  18828.      }
  18829.      return((LATOM)ul);
  18830.  }
  18831.  
  18832.  
  18833.  /*
  18834.   * This routine extracts the hszItem out of an existing hData handle.
  18835.   * local conversations can use the hsz directly out of the handle while
  18836.   * non-dll conversations will have to generate the hsz from the string.
  18837.   */
  18838.  HSZ GetHszItem(
  18839.  PMYDDES pmyddes,
  18840.  PCONVCONTEXT pCC,
  18841.  BOOL fAdd)
  18842.  {
  18843.      if (CheckSel(SELECTOROF(pmyddes)) >= sizeof(MYDDES) &&
  18844.              pmyddes->magic == MYDDESMAGIC) {
  18845.          if (fAdd)
  18846.              IncHszCount(pmyddes->hszItem);
  18847.          return(pmyddes->hszItem);
  18848.      } else {
  18849.          return(GetHsz(DDES_PSZITEMNAME(pmyddes), pCC->idCountry,
  18850.                  pCC->usCodepage, fAdd));
  18851.      }
  18852.  }
  18853.  
  18854.  
  18855.  DMGMON.C
  18856.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGMON.C
  18857.  
  18858.  /****************************** Module Header ******************************\
  18859.  * Module Name: DMGMON.C
  18860.  *
  18861.  * This module contains functions used for DDE monitor control.
  18862.  *
  18863.  * Created:  8/2/88    sanfords
  18864.  *
  18865.  * Copyright (c) 1988, 1989  Microsoft Corporation
  18866.  \***************************************************************************/
  18867.  #include "ddemlp.h"
  18868.  #define MSGF_DDEPOSTMSG     3
  18869.  
  18870.  #define freeMonStr(psz) MyFreeMem(hheapDmg, (NPBYTE)(USHORT)psz, MAX_MONITORS
  18871.  
  18872.  
  18873.  BOOL EXPENTRY DdeSendHookProc(hab, psmh, fInterTask)
  18874.  HAB hab;
  18875.  PSMHSTRUCT psmh;
  18876.  BOOL fInterTask;
  18877.  {
  18878.      PSZ psz;
  18879.      PSZ pszSave;
  18880.      PSZ pszLast;
  18881.  
  18882.      UNUSED hab;
  18883.      UNUSED fInterTask;
  18884.  
  18885.      if (psmh->msg == WM_DDE_INITIATE || psmh->msg == WM_DDE_INITIATEACK) {
  18886.          if (allocMonStr(&pszSave, &pszLast)) {
  18887.              psz = timestamp(pszSave, pszLast);
  18888.              psz = lstrcat(psz, " ", pszLast);
  18889.              psz = ltoa((ULONG)psmh->mp1, psz, pszLast);
  18890.              psz = lstrcat(psz, " -> ", pszLast);
  18891.              psz = ltoa((ULONG)psmh->hwnd, psz, pszLast);
  18892.              psz = lstrcat(psz, "\n\r", pszLast);
  18893.              psz = ddeMsgToPsz(psmh->msg, psz, pszLast);
  18894.              psz = pddesToPsz(psmh->msg, (PDDESTRUCT)psmh->mp2, psz, pszLast);
  18895.              psz = lstrcat(psz, ")\n\r", pszLast);
  18896.              MonitorBroadcast(pszSave);
  18897.              freeMonStr(pszSave);
  18898.          }
  18899.      }
  18900.      return(FALSE);
  18901.  }
  18902.  
  18903.  
  18904.  
  18905.  
  18906.  BOOL EXPENTRY DdePostHookProc(hab, pqmsg, fs)
  18907.  HAB hab;
  18908.  PQMSG pqmsg;
  18909.  USHORT fs;
  18910.  {
  18911.      PSZ psz;
  18912.      PSZ pszSave;
  18913.      PSZ pszLast;
  18914.  
  18915.      UNUSED hab;
  18916.  
  18917.      if (fs && pqmsg->msg >= WM_DDE_FIRST && pqmsg->msg <= WM_DDE_LAST) {
  18918.          pszLast = psz + MAX_MONITORSTR;
  18919.          if (allocMonStr(&pszSave, &pszLast)) {
  18920.              psz = timestamp(pszSave, pszLast);
  18921.              psz = lstrcat(psz, " ", pszLast);
  18922.              psz = ltoa((ULONG)pqmsg->mp1, psz, pszLast);
  18923.              psz = lstrcat(psz, " -> ", pszLast);
  18924.              psz = ltoa((ULONG)pqmsg->hwnd, psz, pszLast);
  18925.              psz = lstrcat(psz, "\n\r", pszLast);
  18926.              psz = ddeMsgToPsz(pqmsg->msg, psz, pszLast);
  18927.              psz = pddesToPsz(pqmsg->msg, (PDDESTRUCT)pqmsg->mp2, psz, pszLast
  18928.              psz = lstrcat(psz, ")\n\r", pszLast);
  18929.              MonitorBroadcast(pszSave);
  18930.              freeMonStr(pszSave);
  18931.          }
  18932.      }
  18933.      return(FALSE);
  18934.  }
  18935.  
  18936.  /*
  18937.   * This guy sends a UM_MONITOR to all the monitor windows (up to MAX_MONITOR)
  18938.   * The cheap restriction is due to needing to not be in the semaphore
  18939.   * while the monitor is in control yet needing to keep access to pai in
  18940.   * the semaphore.
  18941.   */
  18942.  void MonitorBroadcast(psz)
  18943.  PSZ psz;
  18944.  {
  18945.      HWND hwnd[MAX_MONITORS];
  18946.      PAPPINFO pai;
  18947.      register USHORT i = 0;
  18948.  
  18949.      SemCheckOut();
  18950.      SemEnter();
  18951.      pai = pAppInfoList;
  18952.      while (pai && i < cMonitor && i < MAX_MONITORS) {
  18953.          if (pai->hwndMonitor) {
  18954.              hwnd[i] = pai->hwndMonitor;
  18955.              i++;
  18956.          }
  18957.          pai = pai->next;
  18958.      }
  18959.      SemLeave();
  18960.  
  18961.      for (i = 0; i < cMonitor; i++)
  18962.          WinSendMsg(hwnd[i], UM_MONITOR, (MPARAM)psz, 0L);
  18963.  }
  18964.  
  18965.  
  18966.  /*
  18967.   * We need to allocate the string buffer so that recursive calls will work.
  18968.   * We also need to do this because the DLL DS is shared between all potential
  18969.   * monitor processes.
  18970.   *
  18971.   * This also initializes the psz for us with a null terminator and checks
  18972.   * cMonitor for us.  If this fails, no monitor action is done.
  18973.   *
  18974.   * ppsz will contain a pointer to the begining of the allocated buffer.
  18975.   * ppszLast will contain a pointer to the end of the allocated buffer.
  18976.   */
  18977.  BOOL allocMonStr(ppsz, ppszLast)
  18978.  PSZ far *ppsz;
  18979.  PSZ far *ppszLast;
  18980.  {
  18981.      SemEnter();
  18982.      if (cMonitor == 0 ||
  18983.              ((*ppsz = FarAllocMem(hheapDmg, MAX_MONITORSTR + 1)) == NULL)) {
  18984.          SemLeave();
  18985.          return(FALSE);
  18986.      }
  18987.      *ppszLast = *ppsz + MAX_MONITORSTR;
  18988.      **ppsz = '\0';
  18989.      SemLeave();
  18990.      return(TRUE);
  18991.  }
  18992.  
  18993.  
  18994.  
  18995.  MRESULT EXPENTRY MonitorWndProc(hwnd, msg, mp1, mp2)
  18996.  HWND hwnd;
  18997.  USHORT msg;
  18998.  register MPARAM mp1;
  18999.  MPARAM mp2;
  19000.  {
  19001.      PAPPINFO pai;
  19002.      HDMGDATA hDmgData;
  19003.  
  19004.      pai = GetCurrentAppInfo(FALSE);
  19005.  
  19006.      switch (msg) {
  19007.      case WM_CREATE:
  19008.          mp1  = (PSZ)"\n\rMonitor Created\n\r\n\r";
  19009.          goto MonOut;
  19010.          break;
  19011.  
  19012.      case WM_DESTROY:
  19013.          mp1 = (PSZ)"\n\r\n\rMonitor Destroyed\n\r";
  19014.          /* fall through */
  19015.  
  19016.      case UM_MONITOR:
  19017.          /*
  19018.           * mp1 = psz to print
  19019.           */
  19020.  MonOut:
  19021.          hDmgData = DdePutData((PSZ)mp1, (ULONG)(lstrlen(mp1) + 1),
  19022.                  0L, (HSZ)0L, DDEFMT_TEXT, 0);
  19023.          pai->cInCallback++;
  19024.          DoCallback(pai, 0, 0, 0, DDEFMT_TEXT, XTYP_MONITOR, hDmgData);
  19025.          if (pai->cInCallback > 0)   /* test incase exitlist processing messed
  19026.              pai->cInCallback--;
  19027.          break;
  19028.  
  19029.      default:
  19030.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  19031.          break;
  19032.      }
  19033.  
  19034.      return(0);
  19035.  }
  19036.  
  19037.  
  19038.  
  19039.  
  19040.  DMGQ.C
  19041.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGQ.C
  19042.  
  19043.  /****************************** Module Header ******************************\
  19044.  * Module Name: DMGQ.C
  19045.  *
  19046.  * DDE Manager queue control functions.
  19047.  *
  19048.  * Created: 9/1/89 Sanford Staab
  19049.  *
  19050.  * This is a general queue manager - yes another one!
  19051.  * Queues are each allocated within their own segment and have a
  19052.  * QST structure associated with that heap.  Each queue item
  19053.  * is allocated within the heap segment.  The offset of the items
  19054.  * address combined with an instance count is used as the item ID.
  19055.  * This is both unique and allows for instant location of an item.
  19056.  * New items are added to the head of the queue which is a doubly linked
  19057.  * list.  The next links point to more recent entries, the prev pointers
  19058.  * to older entries.  The next of the head is the tail.  The prev of the
  19059.  * tail is the head.  All pointers are far.
  19060.  * Queue Data may be of any structure type that begins identical to
  19061.  * a QUEUEITEM structure.  Functions that require an cbItem perameter
  19062.  * should be given the size of the specialized queue item structure.
  19063.  *
  19064.  * Copyright (c) 1988, 1989  Microsoft Corporation
  19065.  \***************************************************************************/
  19066.  
  19067.  #include "ddemlp.h"
  19068.  
  19069.  
  19070.  /***************************** Private Function ****************************\
  19071.  *
  19072.  * Creates a Queue for items of cbItem.
  19073.  * Returns NULL on error.
  19074.  *
  19075.  *
  19076.  * History:
  19077.  *   Created     9/1/89    Sanfords
  19078.  \***************************************************************************/
  19079.  PQST CreateQ(cbItem)
  19080.  USHORT cbItem;
  19081.  {
  19082.      QST cq;
  19083.      PQST pQ;
  19084.  
  19085.      cq.cItems = 0;
  19086.      cq.instLast = 0;
  19087.      cq.cbItem = cbItem;
  19088.      cq.pqiHead = NULL;
  19089.      if (!(cq.hheap = MyCreateHeap(0, sizeof(QST) + cbItem << 3,
  19090.              cbItem << 3, cbItem, cbItem, HEAPFLAGS)))
  19091.          return(NULL);
  19092.      if (!(pQ = (PQST)FarAllocMem(cq.hheap, sizeof(QST)))) {
  19093.          MyDestroyHeap(cq.hheap);
  19094.          return(0);
  19095.      }
  19096.      *pQ = cq;
  19097.      return(pQ);
  19098.  }
  19099.  
  19100.  
  19101.  
  19102.  /***************************** Private Function ****************************\
  19103.  *
  19104.  *
  19105.  * History:
  19106.  *   Created     9/1/89    Sanfords
  19107.  \***************************************************************************/
  19108.  BOOL DestroyQ(pQ)
  19109.  PQST pQ;
  19110.  {
  19111.      if (pQ)
  19112.          MyDestroyHeap(pQ->hheap);
  19113.      return(TRUE);
  19114.  }
  19115.  
  19116.  
  19117.  
  19118.  /***************************** Private Function ****************************\
  19119.  *
  19120.  * returns a long pointer to the queue item data created.  The new item
  19121.  * is added to the head of the queue.  The queue's cbItem specified at
  19122.  * creation is used for allocation.
  19123.  *
  19124.  *
  19125.  * History:
  19126.  *   Created     9/1/89    Sanfords
  19127.  \***************************************************************************/
  19128.  PQUEUEITEM Addqi(pQ)
  19129.  PQST pQ;
  19130.  {
  19131.      PQUEUEITEM pqi;
  19132.  
  19133.      if ((pqi = (PQUEUEITEM)FarAllocMem(pQ->hheap, pQ->cbItem)) == NULL) {
  19134.          if (pQ->cItems == 0)
  19135.              return(0);
  19136.          /*
  19137.           * remove the oldest item to make room for the new.
  19138.           */
  19139.          pqi = pQ->pqiHead->next;
  19140.          SemEnter();
  19141.          pqi->prev->next = pqi->next;
  19142.          pqi->next->prev = pqi->prev;
  19143.          SemLeave();
  19144.      }
  19145.  
  19146.      SemEnter();
  19147.      if (pQ->cItems == 0) {
  19148.          pQ->pqiHead = pqi->prev = pqi->next = pqi;
  19149.      } else {
  19150.          pqi->prev = pQ->pqiHead;
  19151.          pqi->next = pQ->pqiHead->next;
  19152.          pQ->pqiHead->next->prev = pqi;
  19153.          pQ->pqiHead->next = pqi;
  19154.          pQ->pqiHead = pqi;
  19155.      }
  19156.      SemLeave();
  19157.      pQ->cItems++;
  19158.      pqi->inst = ++pQ->instLast;
  19159.      return(pqi);
  19160.  }
  19161.  
  19162.  
  19163.  
  19164.  
  19165.  /***************************** Private Function ****************************\
  19166.  *
  19167.  *  The id given is an external LONG id, not an item instance number.
  19168.  *  If id is QID_NEWEST, the head item is deleted.
  19169.  *  If id is QID_OLDEST, the tail item is deleted.
  19170.  *
  19171.  *
  19172.  * History:
  19173.  *   Created     9/1/89    Sanfords
  19174.  \***************************************************************************/
  19175.  void Deleteqi(pQ, id)
  19176.  PQST pQ;
  19177.  ULONG id;
  19178.  {
  19179.      PQUEUEITEM pqi;
  19180.  
  19181.      SemEnter();
  19182.      pqi = Findqi(pQ, id);
  19183.      if (pqi == NULL) {
  19184.          SemLeave();
  19185.          return;
  19186.      }
  19187.      pqi->prev->next = pqi->next;
  19188.      pqi->next->prev = pqi->prev;
  19189.      if (pqi == pQ->pqiHead)
  19190.          pQ->pqiHead = pqi->prev;
  19191.      if (!(--pQ->cItems))
  19192.          pQ->pqiHead = NULL;
  19193.      FarFreeMem(pQ->hheap, pqi, pQ->cbItem);
  19194.      SemLeave();
  19195.  }
  19196.  
  19197.  
  19198.  
  19199.  
  19200.  
  19201.  
  19202.  /***************************** Private Function ****************************\
  19203.  *
  19204.  *  The id given is an external LONG id, not an item instance number.
  19205.  *
  19206.  *  if id == QID_NEWEST, returns the head queue data item.
  19207.  *  if id == QID_OLDEST, returns the tail queue data item.
  19208.  *  if the id is not found or the queue is empty, NULL is returned.
  19209.  *  if found, pqi is returned.
  19210.  *
  19211.  *
  19212.  * History:
  19213.  *   Created     9/1/89    Sanfords
  19214.  \***************************************************************************/
  19215.  PQUEUEITEM Findqi(pQ, id)
  19216.  PQST pQ;
  19217.  ULONG id;
  19218.  {
  19219.      PQUEUEITEM pqi;
  19220.  
  19221.      SemCheckIn();
  19222.      if (pQ == NULL || pQ->pqiHead == NULL)
  19223.          return(NULL);
  19224.  
  19225.      if (id == QID_OLDEST)
  19226.          return(pQ->pqiHead->next);
  19227.  
  19228.      if (id == QID_NEWEST)
  19229.          return(pQ->pqiHead);
  19230.  
  19231.      if (id) {
  19232.          pqi = PFROMID(pQ, id);
  19233.          if (pqi->inst == HIUSHORT(id)) {
  19234.              return(pqi);
  19235.          }
  19236.          return(NULL);
  19237.      }
  19238.  }
  19239.  
  19240.  
  19241.  DMGSTR.C
  19242.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGSTR.C
  19243.  
  19244.  /****************************** Module Header ******************************\
  19245.  * Module Name: DMGSTR.C
  19246.  *
  19247.  * DDE manager string handling routines
  19248.  *
  19249.  * Created: 1/31/88 Sanford Staab
  19250.  *
  19251.  * Copyright (c) 1988, 1989  Microsoft Corporation
  19252.  \***************************************************************************/
  19253.  #include "ddemlp.h"
  19254.  #include "ctype.h"
  19255.  
  19256.  
  19257.  
  19258.  /***************************** Private Function ****************************\
  19259.  *
  19260.  * returns string length not counting null terminator.
  19261.  *
  19262.  * History:  1/1/89  created     sanfords
  19263.  \***************************************************************************/
  19264.  int lstrlen(psz)
  19265.  PSZ psz;
  19266.  {
  19267.      int c = 0;
  19268.  
  19269.      while (*psz != 0) {
  19270.          psz++;
  19271.          c++;
  19272.      }
  19273.      return(c);
  19274.  }
  19275.  
  19276.  /***************************** Public  Function ****************************\
  19277.  * Concatonates psz1 and psz2 into psz1.
  19278.  * returns psz pointing to end of concatonated string.
  19279.  * pszLast marks point at which copying must stop.  This makes this operation
  19280.  * safe for limited buffer sizes.
  19281.  *
  19282.  * History:  1/1/89  created sanfords
  19283.  \***************************************************************************/
  19284.  PSZ lstrcat(psz1, psz2, pszLast)
  19285.  PSZ psz1, psz2, pszLast;
  19286.  {
  19287.      psz1 += lstrlen(psz1);
  19288.      while (*psz2 != '\0' && psz1 < pszLast) {
  19289.          *psz1++ = *psz2++;
  19290.      }
  19291.      *psz1 = '\0';
  19292.      return(psz1);
  19293.  }
  19294.  
  19295.  /***************************** Private Function ****************************\
  19296.  * DESCRIPTION: ASCII dependent converter of DDE structure data to a string.
  19297.  * returns psz pointing to end of copy.
  19298.  * During monitoring we allocate segments as gettable so we can monitor them.
  19299.  *
  19300.  * History:      Created 1/31/89         sanfords
  19301.  \***************************************************************************/
  19302.  PSZ pddesToPsz(msg, pddes, psz, pszLast)
  19303.  USHORT msg;
  19304.  PDDESTRUCT pddes;
  19305.  PSZ psz;
  19306.  PSZ pszLast;
  19307.  {
  19308.      USHORT cb;
  19309.      PBYTE pData;
  19310.  #define pDdeInit ((PDDEINIT)pddes)
  19311.  
  19312.      *psz = '\0';
  19313.      switch (msg) {
  19314.      case WM_DDE_REQUEST:
  19315.      case WM_DDE_ACK:
  19316.      case WM_DDE_DATA:
  19317.      case WM_DDE_ADVISE:
  19318.      case WM_DDE_UNADVISE:
  19319.      case WM_DDE_POKE:
  19320.      case WM_DDE_EXECUTE:
  19321.          psz = lstrcat(psz, "S:", pszLast);
  19322.          psz = Status(pddes->fsStatus, psz, pszLast);
  19323.          psz = lstrcat(psz, " F:", pszLast);
  19324.          psz = Format(pddes->usFormat, psz, pszLast);
  19325.          psz = lstrcat(psz, " I:", pszLast);
  19326.          psz = lstrcat(psz, DDES_PSZITEMNAME(pddes), pszLast);
  19327.          if (pddes->cbData)
  19328.              psz = lstrcat(psz, "\n\r  Data:", pszLast);
  19329.          pData = DDES_PABDATA(pddes);
  19330.  
  19331.          for (cb = 0; (ULONG)cb < pddes->cbData && psz < pszLast; cb++, pData+
  19332.              /*
  19333.               * new line every 64 chars
  19334.               */
  19335.              if ((cb & 0x3F) == 0) {
  19336.                  *psz = '\0';
  19337.                  psz = lstrcat(psz, "\n\r    ", pszLast);
  19338.              }
  19339.              if (*pData > 0x20)
  19340.                  *psz = *pData;
  19341.              else
  19342.                  *psz = '.';
  19343.  
  19344.              *psz++ = *psz & 0x7f;
  19345.          }
  19346.          CopyBlock("\n\r", pszLast - 3, 3L);
  19347.          break;
  19348.  
  19349.      case WM_DDE_INITIATEACK:
  19350.      case WM_DDE_INITIATE:
  19351.          if (CheckSel(SELECTOROF(pDdeInit))) {
  19352.              psz = lstrcat(psz, "A:", pszLast);
  19353.              psz = lstrcat(psz, pDdeInit->pszAppName, pszLast);
  19354.              psz = lstrcat(psz, " T:", pszLast);
  19355.              psz = lstrcat(psz, pDdeInit->pszTopic, pszLast);
  19356.          }
  19357.          break;
  19358.  
  19359.      case WM_DDE_TERMINATE:
  19360.          break;
  19361.      }
  19362.      *psz = '\0';
  19363.      return(psz);
  19364.  
  19365.  #undef pDdeInit
  19366.  
  19367.  }
  19368.  
  19369.  
  19370.  PSZ Status(fs, psz, pszLast)
  19371.  USHORT fs;
  19372.  PSZ psz;
  19373.  PSZ pszLast;
  19374.  {
  19375.      if (fs & DDE_FACK) {
  19376.          psz = lstrcat(psz, "ACK ", pszLast);
  19377.      }
  19378.      if (fs & DDE_FBUSY) {
  19379.          psz = lstrcat(psz, "BUSY ", pszLast);
  19380.      }
  19381.      if (fs & DDE_FNODATA) {
  19382.          psz = lstrcat(psz, "NODATA ", pszLast);
  19383.      }
  19384.      if (fs & DDE_FACKREQ) {
  19385.          psz = lstrcat(psz, "ACKREQ ", pszLast);
  19386.      }
  19387.      if (fs & DDE_FRESPONSE) {
  19388.          psz = lstrcat(psz, "RESPONSE ", pszLast);
  19389.      }
  19390.      if (fs & DDE_NOTPROCESSED) {
  19391.          psz = lstrcat(psz, "NOTPROCESSED ", pszLast);
  19392.      }
  19393.      if (fs & DDE_FAPPSTATUS) {
  19394.          psz = lstrcat(psz, "APPSTAT=", pszLast);
  19395.          psz = itoa(fs & DDE_FAPPSTATUS, psz, pszLast);
  19396.          *psz++ = ' ';
  19397.          *psz++ = '\0';
  19398.      }
  19399.      if (fs & DDE_FRESERVED) {
  19400.          psz = lstrcat(psz, "RESERVED=", pszLast);
  19401.          psz = itoa(fs & DDE_FRESERVED, psz, pszLast);
  19402.      }
  19403.      return(psz);
  19404.  }
  19405.  
  19406.  
  19407.  PSZ Format(fmt, psz, pszLast)
  19408.  USHORT fmt;
  19409.  PSZ psz;
  19410.  PSZ pszLast;
  19411.  {
  19412.      if (fmt > 0xbfff) {
  19413.          *psz++ = '"';
  19414.          psz += WinQueryAtomName(WinQuerySystemAtomTable(), fmt, psz, pszLast
  19415.          *psz++ = '"';
  19416.          *psz = '\0';
  19417.      } else if (fmt == DDEFMT_TEXT) {
  19418.          psz = lstrcat(psz, "TEXT", pszLast);
  19419.      } else {
  19420.          psz = itoa(fmt, psz, pszLast);
  19421.      }
  19422.      return(psz);
  19423.  }
  19424.  
  19425.  
  19426.  
  19427.  
  19428.  /***************************** Private Function ****************************\
  19429.  * DESCRIPTION: puts an apropriate string for a DDE message into psz. pszLast
  19430.  * specifies the last spot to copy.  Returns a psz pointing to the end of
  19431.  * the copyed data.
  19432.  *
  19433.  * History:      Created 1/31/89         sanfords
  19434.  \***************************************************************************/
  19435.  PSZ ddeMsgToPsz(msg, psz, pszLast)
  19436.  USHORT msg;
  19437.  PSZ psz;
  19438.  PSZ pszLast;
  19439.  {
  19440.      psz = lstrcat(psz, " ", pszLast);
  19441.      if (msg < WM_DDE_FIRST || msg > WM_DDE_LAST) {
  19442.          psz = itoa(msg, psz, pszLast);
  19443.      } else {
  19444.          WinLoadString(DMGHAB, hmodDmg, msg, pszLast - psz + 1, psz);
  19445.          psz += lstrlen(psz);
  19446.      }
  19447.      return(lstrcat(psz, "(", pszLast));
  19448.  }
  19449.  
  19450.  /***************************** Private Function ****************************\
  19451.  * DESCRIPTION:
  19452.  *   fills psz with a hex string "0xdddd" and returns psz pointing to the 0
  19453.  *   terminator at the end.  copying will never go beyond pszLast.
  19454.  *
  19455.  * History:      Created 1/31/89        sanfords
  19456.  \***************************************************************************/
  19457.  PSZ itoa(us, psz, pszLast)
  19458.  USHORT us;
  19459.  PSZ psz;
  19460.  PSZ pszLast;
  19461.  {
  19462.      if (psz > pszLast - 7)
  19463.          return(psz);
  19464.      *psz++ = '0';
  19465.      *psz++ = 'x';
  19466.      return(stoa(psz, us));
  19467.  }
  19468.  
  19469.  /***************************** Private Function ****************************\
  19470.  * DESCRIPTION:
  19471.  *   fills psz with a hex string "0xdddddddd" and returns psz pointing to the
  19472.  *   terminator at the end.  copying will never go beyond pszLast.
  19473.  *
  19474.  * History:      Created 1/31/89        sanfords
  19475.  \***************************************************************************/
  19476.  PSZ ltoa(ul, psz, pszLast)
  19477.  ULONG ul;
  19478.  PSZ psz;
  19479.  PSZ pszLast;
  19480.  {
  19481.      if (psz > pszLast - 11)
  19482.          return(psz);
  19483.      *psz++ = '0';
  19484.      *psz++ = 'x';
  19485.      psz = stoa(psz, HIUSHORT(ul));
  19486.      return(stoa(psz, LOUSHORT(ul)));
  19487.  }
  19488.  
  19489.  
  19490.  /***************************** Private Function ****************************\
  19491.  * DESCRIPTION:
  19492.  *   fills psz with a hex string "dddd" and returns psz pointing to the 0
  19493.  *   terminator at the end.
  19494.  *
  19495.  * History:      Created 1/31/89        sanfords
  19496.  \***************************************************************************/
  19497.  PSZ stoa(psz, us)
  19498.  PSZ psz;
  19499.  USHORT us;
  19500.  {
  19501.      static char dtoa[] = "0123456789abcdef";
  19502.  
  19503.      *psz++ = dtoa[(us & 0xf000) >> 12];
  19504.      *psz++ = dtoa[(us & 0xf00) >> 8];
  19505.      *psz++ = dtoa[(us & 0xf0) >> 4];
  19506.      *psz++ = dtoa[us & 0xf];
  19507.      *psz = '\0';
  19508.      return(psz);
  19509.  }
  19510.  
  19511.  
  19512.  /*
  19513.   * Decimal to ascii
  19514.   */
  19515.  PSZ dtoa(psz, us, fRecurse)
  19516.  PSZ psz;
  19517.  USHORT us;
  19518.  BOOL fRecurse;
  19519.  {
  19520.      if (us > 9) {
  19521.          psz = dtoa(psz, us / 10, TRUE);
  19522.          *psz++ = (UCHAR)(us % 10) + '0';
  19523.      } else if (us > 0)
  19524.          *psz++ = (UCHAR)us + '0';
  19525.      else if (!fRecurse)
  19526.          *psz++ = '0';
  19527.      *psz = '\000';
  19528.      return(psz);
  19529.  }
  19530.  
  19531.  
  19532.  /***************************** Private Function ****************************\
  19533.  * DESCRIPTION:
  19534.  *   fills psz with a hex time stamp and returns psz pointing to the 0
  19535.  *   terminator at the end.
  19536.  *
  19537.  * History:      Created 5/9/89        sanfords
  19538.  \***************************************************************************/
  19539.  PSZ timestamp(psz, pszLast)
  19540.  PSZ psz;
  19541.  PSZ pszLast;
  19542.  {
  19543.      DATETIME dt;
  19544.      static USHORT prevTime = 0;
  19545.      USHORT Time;
  19546.  
  19547.      DosGetDateTime(&dt);
  19548.      Time = MAKESHORT(dt.hundredths, dt.seconds);
  19549.      psz = lstrcat(psz, "----------- dTime=", pszLast);
  19550.      psz = itoa(Time - prevTime, psz, pszLast);
  19551.      psz = lstrcat(psz, " ", pszLast);
  19552.      prevTime = Time;
  19553.      return(psz + lstrlen(psz));
  19554.  }
  19555.  
  19556.  
  19557.  DMGSTRT.ASM
  19558.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGSTRT.ASM
  19559.  
  19560.  ;  DDE manager library initialization routine
  19561.  
  19562.  .286p
  19563.  
  19564.  ?WIN=1      ; Use Windows prolog/epilog
  19565.  ?PLM=1      ; Use PLM calling convention
  19566.  DOS5=1
  19567.  .xlist
  19568.  include cmacros.inc
  19569.  .list
  19570.  
  19571.  sBegin  DATA
  19572.  
  19573.  assumes DS,DATA
  19574.  
  19575.  externW hmodDmg
  19576.  externW usHugeShift
  19577.  
  19578.  sEnd    DATA
  19579.  
  19580.  sBegin  CODE
  19581.  assumes cs,CODE
  19582.  assumes ds,DATA
  19583.  
  19584.  externNP        SemInit
  19585.  
  19586.  ;
  19587.  ; Registers set up by DosLoadModule...
  19588.  ;
  19589.  ;   SI = heap size
  19590.  ;   DI = module ID
  19591.  ;   DS = library's automatic data segment
  19592.  ;
  19593.  cProc   LoadProc,<FAR,PUBLIC>
  19594.  cBegin  LoadProc
  19595.  ;       int     3
  19596.          mov     hmodDmg, di
  19597.          call    SemInit
  19598.  cEnd    LoadProc
  19599.  
  19600.  ;
  19601.  ; FillBlock(PBYTE pDst, USHORT cb, BYTE b)
  19602.  ;
  19603.  cProc        FillBlock,<PUBLIC, NEAR>,<DI, DS>
  19604.  ParmD        pDst
  19605.  ParmW        cb
  19606.  ParmW        b
  19607.  cBegin
  19608.          les        di,pDst
  19609.          mov        cx,cb
  19610.          mov        ax,b
  19611.          cld
  19612.          rep        stosb
  19613.  cEnd
  19614.  
  19615.  ;
  19616.  ; CopyBlock(pbSrc, pbDst, cb)
  19617.  ;
  19618.  LabelNP <PUBLIC, CopyBlock>
  19619.          mov     bx,sp
  19620.          push    si
  19621.          push    di
  19622.          mov     dx,ds               ; preserve DS
  19623.  
  19624.          mov     cx,ss:[bx+2]
  19625.          jcxz    copydone           ; all done if crc   == 0
  19626.          les     di,ss:[bx+2+2]
  19627.          lds     si,ss:[bx+2+2+4]
  19628.          cmp     si,di
  19629.          jae     copyok
  19630.          mov     ax,cx
  19631.          dec     ax
  19632.          add     si,ax
  19633.          add     di,ax
  19634.          std
  19635.          rep     movsb
  19636.          cld
  19637.          jmp     short copydone
  19638.  copyok:
  19639.          cld
  19640.          rep     movsb
  19641.  copydone:
  19642.  
  19643.          mov     ds,dx
  19644.          pop     di
  19645.          pop     si
  19646.          ret     10
  19647.  
  19648.  
  19649.  cProc HugeOffset,<NEAR, PUBLIC>
  19650.  parmD   pSrc
  19651.  parmD   cb
  19652.  cBegin
  19653.          mov     dx, SEG_cb
  19654.          mov     ax, OFF_pSrc
  19655.          add     ax, OFF_cb
  19656.          adc     dx, 0
  19657.          mov     cx, usHugeShift
  19658.          shl     dx, cl
  19659.          add     dx, SEG_pSrc
  19660.  cEnd
  19661.  
  19662.  
  19663.  LabelFP <PUBLIC, DdeDebugBreak>
  19664.          int     3
  19665.          retf    0
  19666.  
  19667.  ;
  19668.  ; Returns segment size or 0 on error.
  19669.  ;
  19670.  LabelNP <PUBLIC, CheckSel>
  19671.  ;    parmW   Selector    ; selector to validate
  19672.  cBegin  nogen
  19673.          mov     bx,sp               ; BX = selector to validate
  19674.          mov     bx,ss:[bx].2
  19675.          lar     ax,bx               ; See if valid selector
  19676.          jnz     invalid_selector
  19677.  
  19678.          lsl     ax,bx
  19679.          or      ax,ax               ; zero sized?
  19680.          jnz     valid_selector      ; nope, ok.
  19681.  
  19682.  invalid_selector:
  19683.          xor     ax,ax               ; Return zero just to be nice
  19684.  
  19685.  valid_selector:
  19686.          ret     2
  19687.  
  19688.  cEnd    nogen
  19689.  
  19690.  sEnd    CODE
  19691.  end     LoadProc
  19692.  
  19693.  
  19694.  DMGWNDP.C
  19695.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\DDEML\DMGWNDP.C
  19696.  
  19697.  /****************************** Module Header ******************************\
  19698.  *
  19699.  * Module Name: DMGWNDP.C
  19700.  *
  19701.  * This module contains all the window procs for the DDE manager.
  19702.  *
  19703.  * Created: 12/23/88 sanfords
  19704.  *
  19705.  * Copyright (c) 1988, 1989  Microsoft Corporation
  19706.  \***************************************************************************/
  19707.  
  19708.  #include "ddemlp.h"
  19709.  
  19710.  
  19711.  ULONG defid = QID_SYNC;
  19712.  XFERINFO defXferInfo = {
  19713.          &defid,
  19714.          1L,
  19715.          XTYP_INIT,
  19716.          DDEFMT_TEXT,
  19717.          0L,
  19718.          0L,
  19719.          0L,
  19720.          NULL
  19721.  };
  19722.  
  19723.  void InitAck(HWND hwnd, PCLIENTINFO pci, HWND hwndServer, PDDEINIT pddei);
  19724.  MRESULT ClientXferReq(PXFERINFO pXferInfo, PCLIENTINFO pci, HWND hwnd);
  19725.  USHORT SendClientReq(PXADATA pXad, HWND hwndServer, HWND hwnd, PAPPINFO pai);
  19726.  void DoClientDDEmsg(PCLIENTINFO pci, HWND hwnd, USHORT msg, HWND hwndFrom,
  19727.          PDDESTRUCT pddes);
  19728.  BOOL fExpectedMsg(PXADATA pXad, PDDESTRUCT pddes, USHORT msg, PCLIENTINFO pci
  19729.  BOOL AdvanceXaction(HWND hwnd, PCLIENTINFO pci, PXADATA pXad,
  19730.          PDDESTRUCT pddes, USHORT msg, PUSHORT pErr);
  19731.  MRESULT ClientXferRespond(PCLIENTINFO pci, PXADATA pXad, PUSHORT pErr);
  19732.  void FrameInitConv(HWND hwndClient, PDDEINIT pddei);
  19733.  
  19734.  /*
  19735.   * ----------------CLIENT SECTION------------------
  19736.   *
  19737.   * Each client conversation has associated with it a window and a queue.
  19738.   * A conversation has one synchronous transaction and may have many
  19739.   * asynchronous transactions.  A transaction is differientiated by its
  19740.   * state and other pertinant data.  A transaction may be synchronous,
  19741.   * asynchronous, (initiated by DdeClientXfer()), or it may be external,
  19742.   * (initiated by an advise loop.)
  19743.   *
  19744.   * A transaction is active if it is in the middle of tranfer, otherwise
  19745.   * it is shutdown.  A shutdown transaction is either successful or
  19746.   * failed.  When an asynchronous transaction shuts down, the client
  19747.   * is notified via the callback function. (XTYP_XFERCOMPLETE)
  19748.   *
  19749.   * The synchronous transaction, when active, is in a timeout loop which
  19750.   * can shut-down the transaction at the end of a predefined time period.
  19751.   * Shutdown synchronous transactions imediately transfer their information
  19752.   * to the client application by returning to DdeClientXfer().
  19753.   *
  19754.   * asynchronous transactions remain in the client queue until removed
  19755.   * by the client application via DdeCheckQueue().
  19756.   *
  19757.   * external transactions take place when the client is in an advise
  19758.   * data loop.  These transactions pass through the callback function to
  19759.   * the client to be accepted.(XTYP_ADVDATA)
  19760.   */
  19761.  
  19762.  
  19763.  /***************************** Private Function ****************************\
  19764.  * MRESULT EXPENTRY ClientWndProc(hwnd, msg, mp1, mp2);
  19765.  *
  19766.  *   This window controls a single DDE conversation from the CLIENT side.
  19767.  *   If closed, it will automaticly abort any conversationn in progress.
  19768.  *   It maintains an internal list of any extra WM_DDEINITIATEACK messages
  19769.  *   it receives so that it can be queried later about this information.
  19770.  *   Any extra WM_DDEINITIATEACK messages comming in will be immediately
  19771.  *   terminated.
  19772.  *   It also maintains an internal list of all items which currently are
  19773.  *   in active ADVISE loops.
  19774.  *
  19775.  * History:
  19776.  *   Created     12/16/88    Sanfords
  19777.  \***************************************************************************/
  19778.  MRESULT EXPENTRY ClientWndProc(hwnd, msg, mp1, mp2)
  19779.  HWND hwnd;
  19780.  USHORT msg;
  19781.  MPARAM mp1;
  19782.  MPARAM mp2;
  19783.  {
  19784.      register PCLIENTINFO pci;
  19785.      PAPPINFO pai;
  19786.      MRESULT mrData;
  19787.      PDDESTRUCT pddes;
  19788.  
  19789.      pci = (PCLIENTINFO)WinQueryWindowULong(hwnd, QWL_USER);
  19790.  
  19791.      switch (msg) {
  19792.      case WM_CREATE:
  19793.          /*
  19794.           * allocate and initialize the client window info.
  19795.           */
  19796.          pai = GetCurrentAppInfo(FALSE);
  19797.          SemEnter();
  19798.          pci = (PCLIENTINFO)FarAllocMem(pai->hheapApp, sizeof(CLIENTINFO));
  19799.          SemLeave();
  19800.          if (pci == NULL) {
  19801.              pai->LastError = DMGERR_MEMORY_ERROR;
  19802.              return(1);          /* aboart creation - low memory */
  19803.          }
  19804.          WinSetWindowULong(hwnd, QWL_USER, (ULONG)pci);
  19805.          pci->ci.pai = pai;
  19806.          pci->ci.xad.state = CONVST_NULL;
  19807.          pci->ci.xad.pXferInfo = &defXferInfo;
  19808.          pci->ci.fs = 0;
  19809.          pci->ci.hwndPartner = NULL;
  19810.          pci->ci.hszServerApp = NULL;
  19811.          pci->ci.hszTopic = NULL;
  19812.          pci->pQ = NULL;    /* don't create until we need one */
  19813.          if (!(pci->ci.pAdviseList = CreateLst(pai->hheapApp, sizeof(ADVLI))))
  19814.              FarFreeMem(pai->hheapApp, (PBYTE)pci, sizeof(CLIENTINFO));
  19815.              pai->LastError = DMGERR_MEMORY_ERROR;
  19816.              return(1);          /* aboart creation - low memory */
  19817.          }
  19818.          break;
  19819.  
  19820.      case UMCL_INITIATE:
  19821.          if (pci->ci.xad.state == CONVST_NULL) {
  19822.              return(ClientInitiate(hwnd, (PINITINFO)mp1, pci));
  19823.          }
  19824.          break;
  19825.  
  19826.      case WM_DDE_INITIATEACK:
  19827.          InitAck(hwnd, pci, mp1, mp2);
  19828.          DosFreeSeg(SELECTOROF(mp2));
  19829.          return(1);
  19830.          break;
  19831.  
  19832.      case WM_DESTROY:
  19833.          SemCheckOut();
  19834.          if (pci->ci.fs & ST_CONNECTED) {
  19835.              /*
  19836.               * stop any advises in progress
  19837.               */
  19838.              if (pci->ci.fs & ST_ADVISE) {
  19839.                  pddes = AllocDDESel(0, 0, 0, 0L, NULL);
  19840.                  MyDdePostMsg(pci->ci.hwndPartner, hwnd, WM_DDE_UNADVISE,
  19841.                          (PMYDDES)pddes, pci->ci.pai, MDPM_FREEHDATA);
  19842.              }
  19843.              WinSendMsg(hwnd, UMCL_TERMINATE, 0L, 0L);
  19844.              /*
  19845.               * decrement the use counts on hszs we are done with.
  19846.               */
  19847.              FreeHsz(pci->ci.hszServerApp);
  19848.              FreeHsz(pci->ci.hszTopic);
  19849.          }
  19850.  
  19851.          DestroyLst(pci->ci.pAdviseList);
  19852.  
  19853.          SemEnter();
  19854.          DestroyQ(pci->pQ);
  19855.          FarFreeMem(pci->ci.pai->hheapApp, (PBYTE)pci, sizeof(CLIENTINFO));
  19856.          SemLeave();
  19857.          break;
  19858.  
  19859.      case UMCL_TERMINATE:
  19860.          /*
  19861.           * terminates any conversation in progress
  19862.           */
  19863.          if (pci->ci.fs & ST_CONNECTED) {
  19864.              pci->ci.fs = pci->ci.fs & ~ST_CONNECTED;
  19865.              pci->ci.xad.state = CONVST_TERMINATED;
  19866.              if (WinIsWindow(DMGHAB, pci->ci.hwndPartner))
  19867.                  WinDdePostMsg(pci->ci.hwndPartner, hwnd, WM_DDE_TERMINATE, 0L
  19868.          }
  19869.          break;
  19870.  
  19871.      case UMCL_XFER:
  19872.          if (!(pci->ci.fs & ST_CONNECTED)) {
  19873.              pci->ci.pai->LastError = DMGERR_NO_CONV_ESTABLISHED;
  19874.              return(0);
  19875.          }
  19876.          return(ClientXferReq((PXFERINFO)mp1, pci, hwnd));
  19877.          break;
  19878.  
  19879.      case WM_DDE_DATA:
  19880.      case WM_DDE_ACK:
  19881.          DoClientDDEmsg(pci, hwnd, msg, (HWND)mp1, (PDDESTRUCT)mp2);
  19882.          break;
  19883.  
  19884.      case WM_DDE_TERMINATE:
  19885.          SemCheckOut();
  19886.          /*
  19887.           * only respond if this is for us.
  19888.           */
  19889.          if ((HWND)mp1 != pci->ci.hwndPartner) {
  19890.             DosFreeSeg(SELECTOROF(mp2));
  19891.             break;
  19892.          }
  19893.          WinSendMsg(hwnd, UMCL_TERMINATE, 0L, 0L);
  19894.          DosFreeSeg(SELECTOROF(mp2));
  19895.          break;
  19896.  
  19897.      case UM_QUERY:
  19898.          /*
  19899.           * LOUSHORT(mp1) = info index.
  19900.           * mp2 = pData.     If pData==0, return data else copy into pData.
  19901.           */
  19902.          switch (LOUSHORT(mp1)) {
  19903.          case Q_STATUS:
  19904.               mrData = (MRESULT)pci->ci.fs;
  19905.               break;
  19906.  
  19907.          case Q_CLIENT:
  19908.               mrData = TRUE;
  19909.               break;
  19910.  
  19911.          case Q_APPINFO:
  19912.               mrData = pci->ci.pai;
  19913.               break;
  19914.  
  19915.          case Q_APPNAME:
  19916.               mrData = *(PHSZ)PTOPPILEITEM(pci->ci.pai->pAppNamePile);
  19917.               break;
  19918.  
  19919.          case Q_ALL:
  19920.               mrData = (MRESULT)(CLIENTINFO FAR *)pci;
  19921.               break;
  19922.          }
  19923.          if (mp2 == 0)
  19924.              return(mrData);
  19925.          else
  19926.              *(MRESULT FAR *)mp2 = mrData;
  19927.          return(1);
  19928.          break;
  19929.  
  19930.      default:
  19931.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  19932.          break;
  19933.      }
  19934.      return(0);
  19935.  }
  19936.  
  19937.  
  19938.  
  19939.  /*
  19940.   * Client response to a WM_DDE_INITIATEACK message when expected.
  19941.   */
  19942.  void InitAck(hwnd, pci, hwndServer, pddei)
  19943.  HWND hwnd;
  19944.  PCLIENTINFO pci;
  19945.  HWND hwndServer;
  19946.  PDDEINIT pddei;
  19947.  {
  19948.      SemCheckOut();
  19949.  
  19950.      if (pci->ci.fs & ST_CONNECTED) {
  19951.          /*
  19952.           * extra server - spawn another client window.  (we assume we
  19953.           * will only get extras if enumerating.)
  19954.           */
  19955.          AssertF(WinQueryWindow(hwnd, QW_PARENT, FALSE) != pci->ci.pai->hwndDm
  19956.              "Improper client spawn")
  19957.          if (hwndServer != pci->ci.hwndPartner) {
  19958.              WinSendMsg(hwndServer, WM_DDE_TERMINATE, hwnd, 0L);
  19959.              GetDDEClientWindow(WinQueryWindow(hwnd, QW_PARENT, FALSE),
  19960.                      hwndServer, hwndServer, pci->ci.hszServerApp,
  19961.                      pci->ci.hszTopic, &pci->ci.cc);
  19962.          }
  19963.          return;
  19964.      }
  19965.  
  19966.      if (pci->ci.xad.state != CONVST_INIT1)
  19967.          return;
  19968.  
  19969.      /*
  19970.       * first one back... lock in!
  19971.       */
  19972.      pci->ci.hwndPartner = hwndServer;
  19973.      pci->ci.xad.state = CONVST_CONNECTED;
  19974.      pci->ci.fs |= ST_CONNECTED;
  19975.      if (WinQueryWindowPtr(hwndServer, QWP_PFNWP) == ServerWndProc)
  19976.          pci->ci.fs |= ST_INTRADLL;
  19977.  
  19978.      /*
  19979.       * If the connection was made using a wild app name, we want to
  19980.       * hack in an apropriate name so QueryConvInfo can give the app
  19981.       * something useful to refer to this guy as.
  19982.       *
  19983.       * - the protocol is little help here.
  19984.       */
  19985.      if (pci->ci.hszServerApp == 0) {
  19986.          if (WinQueryWindowPtr(hwndServer, QWP_PFNWP) == ServerWndProc) {
  19987.              /*
  19988.               * one of ours! simple.
  19989.               */
  19990.              pci->ci.hszServerApp = (PAPPINFO)WinSendMsg(pci->ci.hwndPartner,
  19991.                      UM_QUERY, (MPARAM)Q_APPNAME, 0L);
  19992.          } else {
  19993.              /*
  19994.               * Try the psz in pddei.  Maybe the server set it properly
  19995.               * before returning it.
  19996.               */
  19997.              if (!(pci->ci.hszServerApp =
  19998.                      GetHsz(PSZAPP(pddei), pci->ci.cc.idCountry,
  19999.                              pci->ci.cc.usCodepage, TRUE))) {
  20000.  
  20001.                  PSZ pszT;
  20002.                  USHORT cb;
  20003.  
  20004.                  /*
  20005.                   * WORST CASE:
  20006.                   * Until a better way is found, we set the hszServerApp to
  20007.                   * the title of the frame window.
  20008.                   */
  20009.                  if (pszT = FarAllocMem(pci->ci.pai->hheapApp,
  20010.                          cb = WinQueryWindowTextLength(pci->ci.hwndFrame) + 1)
  20011.                      WinQueryWindowText(pci->ci.hwndFrame, cb, (PSZ)pszT);
  20012.                      pci->ci.hszServerApp = GetHsz(pszT, pci->ci.cc.idCountry,
  20013.                              pci->ci.cc.usCodepage, TRUE);
  20014.                      FarFreeMem(pci->ci.pai->hheapApp, (PBYTE)pszT, cb);
  20015.                  }
  20016.              }
  20017.          }
  20018.      }
  20019.      /*
  20020.       * Now what if the topic was wild?
  20021.       */
  20022.      if (pci->ci.hszTopic == 0) {
  20023.          if (WinQueryWindowPtr(hwndServer, QWP_PFNWP) == ServerWndProc) {
  20024.              /*
  20025.               * one of ours! simple.
  20026.               */
  20027.              pci->ci.hszTopic = (PAPPINFO)WinSendMsg(pci->ci.hwndPartner,
  20028.                      UM_QUERY, (MPARAM)Q_TOPIC, 0L);
  20029.          } else {
  20030.              /*
  20031.               * Try the psz in pddei.  Maybe the server set it properly
  20032.               * before returning it.  If this doesn't work were out of
  20033.               * luck, keep it wild.
  20034.               */
  20035.              pci->ci.hszServerApp = GetHsz(PSZAPP(pddei), pci->ci.cc.idCountry
  20036.                      pci->ci.cc.usCodepage, TRUE);
  20037.          }
  20038.      }
  20039.  }
  20040.  
  20041.  
  20042.  
  20043.  /***************************** Private Function ****************************\
  20044.  * Processes a client transfer request issued by one of the ClientXfer
  20045.  * functions.  This may be synchronous or asynchronous.
  20046.  *
  20047.  * History:
  20048.  *   Created     9/1/89    Sanfords
  20049.  \***************************************************************************/
  20050.  MRESULT ClientXferReq(pXferInfo, pci, hwnd)
  20051.  PXFERINFO pXferInfo;
  20052.  PCLIENTINFO pci;
  20053.  HWND hwnd;
  20054.  {
  20055.      PCQDATA pcqd;
  20056.      MRESULT retVal;
  20057.  
  20058.      if (pXferInfo->ulTimeout == TIMEOUT_ASYNC) {
  20059.          /*
  20060.           * add a client queue item to track this transaction and return
  20061.           * the ID.
  20062.           */
  20063.          if (pci->pQ == NULL)
  20064.              pci->pQ = CreateQ(sizeof(CQDATA));
  20065.          if (pci->pQ == NULL) {
  20066.              pci->ci.pai->LastError = DMGERR_MEMORY_ERROR;
  20067.              return(0);
  20068.          }
  20069.          pcqd = (PCQDATA)Addqi(pci->pQ);
  20070.          if (pcqd == NULL) {
  20071.              pci->ci.pai->LastError = DMGERR_MEMORY_ERROR;
  20072.              return(0);
  20073.          }
  20074.          CopyBlock((PBYTE)pXferInfo, (PBYTE)&pcqd->XferInfo, sizeof(XFERINFO))
  20075.          pcqd->xad.state = CONVST_CONNECTED;
  20076.          pcqd->xad.pddes = 0;
  20077.          pcqd->xad.LastError = DMGERR_NO_ERROR;
  20078.          pcqd->xad.pXferInfo = &pcqd->XferInfo;
  20079.          /*
  20080.           * Get transaction started - if it fails, quit now.
  20081.           */
  20082.          if ((pcqd->xad.LastError = SendClientReq(&pcqd->xad,
  20083.                  pci->ci.hwndPartner, hwnd, pci->ci.pai)) == DMGERR_SERVER_DIE
  20084.              pci->ci.fs = pci->ci.fs & ~ST_CONNECTED;
  20085.              Deleteqi(pci->pQ, MAKEID(pcqd));
  20086.              pci->ci.pai->LastError = DMGERR_SERVER_DIED;
  20087.              return(0);
  20088.          }
  20089.          return((MRESULT)MAKEID(pcqd));
  20090.      }
  20091.  
  20092.      /*
  20093.       * if not quiesent, yet synchronous, tell him were busy.
  20094.       * (this case could happen on a recursive call.)
  20095.       */
  20096.      if (pci->ci.xad.state != CONVST_CONNECTED) {
  20097.          pci->ci.pai->LastError = DMGERR_BUSY;
  20098.          return(0);
  20099.      }
  20100.      /*
  20101.       * Set this so messages comming in during the conversation know whats up
  20102.       */
  20103.      pci->ci.xad.pXferInfo = pXferInfo;
  20104.  
  20105.      if ((pci->ci.pai->LastError = SendClientReq(&pci->ci.xad,
  20106.              pci->ci.hwndPartner, hwnd, pci->ci.pai)) == DMGERR_SERVER_DIED) {
  20107.          pci->ci.fs = pci->ci.fs & ~ST_CONNECTED;
  20108.      }
  20109.  
  20110.      if (pci->ci.pai->LastError != DMGERR_NO_ERROR)
  20111.          return(0);
  20112.      /*
  20113.       *  reset the LastError here so we know if we had problems while
  20114.       *  in the modal loop.
  20115.       */
  20116.      pci->ci.pai->LastError = DMGERR_NO_ERROR;
  20117.      /*
  20118.       * timeout - modal loop.
  20119.       */
  20120.      if (!timeout(pci->ci.pai, pXferInfo->ulTimeout, hwnd)) {
  20121.          /*
  20122.           * reentrency or client has unregistered
  20123.           */
  20124.          return(0);
  20125.      }
  20126.      /*
  20127.       * check results - lasterror already set by timeout().
  20128.       * Synchronous conversation must be reset to quiesent by the time we
  20129.       * give up.
  20130.       */
  20131.      if (pci->ci.xad.state == CONVST_INCOMPLETE) {
  20132.          pci->ci.xad.state = CONVST_CONNECTED;
  20133.          return(0);
  20134.      }
  20135.  
  20136.      retVal = ClientXferRespond(pci, &pci->ci.xad, &pci->ci.pai->LastError);
  20137.      if (pci->ci.xad.state == CONVST_INCOMPLETE)
  20138.          pci->ci.xad.state = CONVST_CONNECTED;
  20139.  
  20140.      return(retVal);
  20141.  }
  20142.  
  20143.  
  20144.  
  20145.  
  20146.  /***************************** Private Function ****************************\
  20147.  * This routine sends the apropriate initiation messages for starting a
  20148.  * client request according to the transaction data given.
  20149.  *
  20150.  * History:
  20151.  *   Created     9/1/89    Sanfords
  20152.  \***************************************************************************/
  20153.  USHORT SendClientReq(pXad, hwndServer, hwnd, pai)
  20154.  PXADATA pXad;
  20155.  HWND hwndServer;
  20156.  HWND hwnd;
  20157.  PAPPINFO pai;
  20158.  {
  20159.      USHORT fsStatus = 0;
  20160.      USHORT msg;
  20161.      BOOL fCopy;
  20162.      PDDESTRUCT pddes;
  20163.  
  20164.      switch (pXad->pXferInfo->usType) {
  20165.      case XTYP_REQUEST:
  20166.          msg = WM_DDE_REQUEST;
  20167.          pXad->state = CONVST_REQSENT;
  20168.          fCopy = FALSE;
  20169.          break;
  20170.  
  20171.      case XTYP_POKE:
  20172.          msg = WM_DDE_POKE;
  20173.          pXad->state = CONVST_POKESENT;
  20174.          fCopy = TRUE;
  20175.          break;
  20176.  
  20177.      case XTYP_EXEC:
  20178.          msg = WM_DDE_EXECUTE;
  20179.          pXad->state = CONVST_EXECSENT;
  20180.          fCopy = TRUE;
  20181.          break;
  20182.  
  20183.      case XTYP_ADVSTART:
  20184.      case XTYP_ADVSTART | XTYPF_NODATA:
  20185.      case XTYP_ADVSTART | XTYPF_ACKREQ:
  20186.      case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  20187.          fsStatus = pXad->pXferInfo->usType & (DDE_FACKREQ | DDE_FNODATA);
  20188.          msg = WM_DDE_ADVISE;
  20189.          pXad->state = CONVST_ADVSENT;
  20190.          fCopy = FALSE;
  20191.          break;
  20192.  
  20193.      case XTYP_ADVSTOP:
  20194.          msg = WM_DDE_UNADVISE;
  20195.          pXad->state = CONVST_UNADVSENT;
  20196.          fCopy = FALSE;
  20197.          break;
  20198.  
  20199.      default:
  20200.          return(DMGERR_INVALIDPARAMETER);
  20201.          break;
  20202.      }
  20203.  
  20204.      /*
  20205.       * Send transfer
  20206.       */
  20207.      if ((pddes = AllocDDESel(fsStatus, pXad->pXferInfo->usFmt,
  20208.              pXad->pXferInfo->hszItem, fCopy ? pXad->pXferInfo->cb : 0, NULL))
  20209.              == 0) {
  20210.          pXad->state = CONVST_CONNECTED;
  20211.          return(DMGERR_MEMORY_ERROR);
  20212.      }
  20213.  
  20214.      if (fCopy)
  20215.          CopyHugeBlock((PBYTE)pXad->pXferInfo->pData, DDES_PABDATA(pddes),
  20216.                  pXad->pXferInfo->cb);
  20217.  
  20218.      if (WinIsWindow(DMGHAB, hwndServer)) {
  20219.          if (!MyDdePostMsg(hwndServer, hwnd, msg, (PMYDDES)pddes, pai, MDPM_FR
  20220.              pXad->state = CONVST_CONNECTED;
  20221.              return(DMGERR_POSTMSG_FAILED);
  20222.          }
  20223.      } else {
  20224.          /*
  20225.           * We lost the server, we are TERMINATED arnold!
  20226.           */
  20227.          pXad->state = CONVST_TERMINATED;
  20228.          FreeData((PMYDDES)pddes, pai);
  20229.          return(DMGERR_SERVER_DIED);
  20230.      }
  20231.      return(DMGERR_NO_ERROR);
  20232.  }
  20233.  
  20234.  
  20235.  
  20236.  
  20237.  
  20238.  /***************************** Private Function ****************************\
  20239.  * This handles client window processing of WM_DDE_ACK and WM_DDE_DATA msgs.
  20240.  * On exit pddes is freed.
  20241.  *
  20242.  * History:
  20243.  *   Created     9/1/89    Sanfords
  20244.  \***************************************************************************/
  20245.  void DoClientDDEmsg(pci, hwnd, msg, hwndFrom, pddes)
  20246.  PCLIENTINFO pci;
  20247.  HWND hwnd;
  20248.  USHORT msg;
  20249.  HWND hwndFrom;
  20250.  PDDESTRUCT pddes;
  20251.  {
  20252.      PCQDATA pqd;
  20253.      int i;
  20254.      HSZ hszItem;
  20255.      PADVLI pAdviseItem;
  20256.  
  20257.      /*
  20258.       * make sure its for us.
  20259.       */
  20260.      if (hwndFrom != pci->ci.hwndPartner || !(pci->ci.fs & ST_CONNECTED)) {
  20261.          FreeData((PMYDDES)pddes, pci->ci.pai);
  20262.          return;
  20263.      }
  20264.      /*
  20265.       * Check if it fits the synchronous transaction data
  20266.       */
  20267.      if (fExpectedMsg(&pci->ci.xad, pddes, msg, pci)) {
  20268.          if (AdvanceXaction(hwnd, pci, &pci->ci.xad, pddes, msg,
  20269.                  &pci->ci.pai->LastError))
  20270.              WinPostMsg(hwnd, WM_TIMER, (MPARAM)TID_TIMEOUT, 0L);
  20271.          return;
  20272.      }
  20273.  
  20274.      /*
  20275.       * See if it fits any asynchronous transaction data - if any exist
  20276.       */
  20277.      if (pci->pQ != NULL && pci->pQ->pqiHead != NULL) {
  20278.          SemEnter();
  20279.          pqd = (PCQDATA)pci->pQ->pqiHead;
  20280.          /*
  20281.           * cycle from oldest to newest.
  20282.           */
  20283.          for (i = pci->pQ->cItems; i; i--) {
  20284.              pqd = (PCQDATA)pqd->next;
  20285.              if (!fExpectedMsg(&pqd->xad, pddes, msg, pci))
  20286.                  continue;
  20287.              if (AdvanceXaction(hwnd, pci, &pqd->xad, pddes, msg,
  20288.                      &pqd->xad.LastError)) {
  20289.                  ClientXferRespond(pci, &pqd->xad, &pqd->xad.LastError);
  20290.                  SemLeave();
  20291.                  MakeCallback(pci->ci.pai, hwnd, (HSZ)0L, (HSZ)0L, 0,
  20292.                          XTYP_XFERCOMPLETE, (HDMGDATA)MAKEID(pqd),
  20293.                          0, 0, hwndFrom);
  20294.                  return;
  20295.              }
  20296.              SemLeave();
  20297.              return;
  20298.          }
  20299.          SemLeave();
  20300.      }
  20301.      /*
  20302.       * It doesn't fit anything, check for an advise data message.
  20303.       */
  20304.      if (msg == WM_DDE_DATA) {
  20305.          hszItem = GetHszItem((PMYDDES)pddes, &pci->ci.cc, TRUE);
  20306.          if (pAdviseItem = (PADVLI)FindAdvList(pci->ci.pAdviseList, hszItem,
  20307.                  pddes->usFormat)) {
  20308.              MakeCallback(pci->ci.pai, (HCONV)hwnd, pci->ci.hszTopic,
  20309.                  hszItem, pddes->usFormat, XTYP_ADVDATA, pddes, msg,
  20310.                  pddes->fsStatus, pci->ci.hwndPartner);
  20311.          } else {
  20312.              FreeHsz(hszItem);
  20313.          }
  20314.          return;
  20315.      }
  20316.      /*
  20317.       * throw it away
  20318.       */
  20319.      FreeData((PMYDDES)pddes, pci->ci.pai);
  20320.      return;
  20321.  }
  20322.  
  20323.  
  20324.  
  20325.  /***************************** Private Function ****************************\
  20326.  * This routine matches a conversation transaction with a DDE message.  If
  20327.  * the state, usType, format, itemname dde structure data and the message
  20328.  * received all agree, TRUE is returned.
  20329.  *
  20330.  * History:
  20331.  *   Created     9/1/89    Sanfords
  20332.  \***************************************************************************/
  20333.  BOOL fExpectedMsg(pXad, pddes, msg, pci)
  20334.  PXADATA pXad;
  20335.  PDDESTRUCT pddes;
  20336.  USHORT msg;
  20337.  PCLIENTINFO pci;
  20338.  {
  20339.      HSZ hsz = 0;
  20340.      BOOL fRet = FALSE;
  20341.  
  20342.      if (!(pXad->state > CONVST_INIT1 &&
  20343.              pddes->usFormat == pXad->pXferInfo->usFmt &&
  20344.              (hsz = GetHszItem((PMYDDES)pddes, &pci->ci.cc, TRUE)) ==
  20345.              pXad->pXferInfo->hszItem)) {
  20346.          goto Exit;
  20347.      }
  20348.      switch (pXad->state) {
  20349.      case CONVST_REQSENT:
  20350.          if (msg == WM_DDE_DATA && !(pddes->fsStatus & DDE_FRESPONSE))
  20351.              /*
  20352.               * Not data in response to a request!
  20353.               */
  20354.              break;
  20355.          fRet = (msg == WM_DDE_ACK || msg == WM_DDE_DATA);
  20356.          break;
  20357.  
  20358.      case CONVST_POKESENT:
  20359.      case CONVST_EXECSENT:
  20360.      case CONVST_ADVSENT:
  20361.      case CONVST_UNADVSENT:
  20362.          fRet = (msg == WM_DDE_ACK);
  20363.          break;
  20364.      }
  20365.  
  20366.  Exit:
  20367.      FreeHsz(hsz);
  20368.      return(fRet);
  20369.  }
  20370.  
  20371.  
  20372.  
  20373.  /***************************** Private Function ****************************\
  20374.  * This function assumes that msg is an apropriate message for the transaction
  20375.  * referenced by pXad.  It acts on msg as apropriate.  pddes is the DDESTRUCT
  20376.  * associated with msg.
  20377.  *
  20378.  * Returns fSuccess ie: transaction is ready to close up.
  20379.  *
  20380.  * History:
  20381.  *   Created     9/1/89    Sanfords
  20382.  \***************************************************************************/
  20383.  BOOL AdvanceXaction(hwnd, pci, pXad, pddes, msg, pErr)
  20384.  HWND hwnd;
  20385.  PCLIENTINFO pci;
  20386.  PXADATA pXad;
  20387.  PDDESTRUCT pddes;
  20388.  USHORT msg;
  20389.  PUSHORT pErr;
  20390.  {
  20391.      switch (msg) {
  20392.      case WM_DDE_ACK:
  20393.          switch (pXad->state) {
  20394.          case CONVST_ADVSENT:
  20395.          case CONVST_EXECSENT:
  20396.          case CONVST_POKESENT:
  20397.          case CONVST_REQSENT:
  20398.          case CONVST_UNADVSENT:
  20399.              if (pddes->fsStatus & DDE_FACK) {
  20400.                  /*
  20401.                   * handle successes
  20402.                   */
  20403.                  switch (pXad->state) {
  20404.                  case CONVST_POKESENT:
  20405.                      pXad->state = CONVST_POKEACKRCVD;
  20406.                      break;
  20407.  
  20408.                  case CONVST_EXECSENT:
  20409.                      pXad->state = CONVST_EXECACKRCVD;
  20410.                      break;
  20411.  
  20412.                  case CONVST_ADVSENT:
  20413.                      pXad->state = CONVST_ADVACKRCVD;
  20414.                      break;
  20415.  
  20416.                  case CONVST_UNADVSENT:
  20417.                      pXad->state = CONVST_UNADVACKRCVD;
  20418.                      break;
  20419.  
  20420.                  case CONVST_REQSENT:
  20421.                      /*
  20422.                       * requests are not expected to send a +ACK.  only
  20423.                       * -ACK or data.  We ignore a +ACK to a request.
  20424.                       */
  20425.                      FreeData((PMYDDES)pddes, pci->ci.pai);
  20426.                      return(FALSE);
  20427.                  }
  20428.              } else {
  20429.                  /*
  20430.                   * handle the expected ACK failures.
  20431.                   */
  20432.                  *pErr = DMGERR_NOTPROCESSED;
  20433.                  if (pddes->fsStatus & DDE_FBUSY)
  20434.                      *pErr = DMGERR_BUSY;
  20435.                  pXad->state = CONVST_INCOMPLETE;
  20436.              }
  20437.          }
  20438.          FreeData((PMYDDES)pddes, pci->ci.pai);
  20439.          return(TRUE);
  20440.          break;
  20441.  
  20442.      case WM_DDE_DATA:
  20443.          switch (pXad->state) {
  20444.          case CONVST_REQSENT:
  20445.              /*
  20446.               * send an ack if requested - we dare not return the given
  20447.               * pddes because it may be a data item sent to several
  20448.               * clients and we would mess up the fsStatus word for
  20449.               * all processes involved.
  20450.               */
  20451.              if (pddes->fsStatus & DDE_FACKREQ) {
  20452.                  MyDdePostMsg(pci->ci.hwndPartner, hwnd, WM_DDE_ACK,
  20453.                          (PMYDDES)AllocDDESel(DDE_FACK, pddes->usFormat,
  20454.                          pXad->pXferInfo->hszItem, 0L, NULL),
  20455.                          pci->ci.pai, MDPM_FREEHDATA);
  20456.              }
  20457.              pXad->state = CONVST_DATARCVD;
  20458.              /*
  20459.               * We do NOT free the selector here yet because it will be
  20460.               * given to the client via pXad->pddes.
  20461.               */
  20462.              pXad->pddes = pddes;
  20463.              return(TRUE);
  20464.              break;
  20465.          }
  20466.      }
  20467.      return(FALSE);
  20468.  }
  20469.  
  20470.  
  20471.  
  20472.  /***************************** Private Function ****************************\
  20473.  * This function assumes that a client transfer request has been completed -
  20474.  * or should be completed by the time this is called.
  20475.  *
  20476.  * pci contains general client info
  20477.  * pXad contains the transaction info
  20478.  * pErr points to where to place the LastError code.
  20479.  *
  20480.  * Returns 0 on failure
  20481.  * Returns TRUE or a Data Selector on success.
  20482.  * On failure, the conversation is left in a CONVST_INCOMPLETE state.
  20483.  * On success, the conversation is left in a CONVST_CONNECTED state.
  20484.  *
  20485.  * History:
  20486.  *   Created     9/1/89    Sanfords
  20487.  \***************************************************************************/
  20488.  MRESULT ClientXferRespond(pci, pXad, pErr)
  20489.  PCLIENTINFO pci;
  20490.  PXADATA pXad;
  20491.  PUSHORT pErr;
  20492.  {
  20493.      if (pXad->state == CONVST_INCOMPLETE)
  20494.          return(0);
  20495.  
  20496.      switch (pXad->pXferInfo->usType) {
  20497.      case XTYP_REQUEST:
  20498.          if (pXad->state != CONVST_DATARCVD) {
  20499.              if (*pErr == DMGERR_NO_ERROR)
  20500.                  *pErr = DMGERR_DATAACKTIMEOUT;
  20501.              goto failexit;
  20502.          }
  20503.          pXad->state = CONVST_CONNECTED;
  20504.          return(pXad->pddes);
  20505.          break;
  20506.  
  20507.      case XTYP_POKE:
  20508.          if (pXad->state != CONVST_POKEACKRCVD) {
  20509.              if (*pErr == DMGERR_NO_ERROR)
  20510.                  *pErr = DMGERR_POKEACKTIMEOUT;
  20511.              goto failexit;
  20512.          }
  20513.          pXad->state = CONVST_CONNECTED;
  20514.          return(TRUE);
  20515.          break;
  20516.  
  20517.      case XTYP_EXEC:
  20518.          if (pXad->state != CONVST_EXECACKRCVD) {
  20519.              if (*pErr == DMGERR_NO_ERROR)
  20520.                  *pErr = DMGERR_EXECACKTIMEOUT;
  20521.              goto failexit;
  20522.          }
  20523.          pXad->state = CONVST_CONNECTED;
  20524.          return(TRUE);
  20525.          break;
  20526.  
  20527.      case XTYP_ADVSTART:
  20528.      case XTYP_ADVSTART | XTYPF_NODATA:
  20529.      case XTYP_ADVSTART | XTYPF_ACKREQ:
  20530.      case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  20531.          if (pXad->state != CONVST_ADVACKRCVD) {
  20532.              if (*pErr == DMGERR_NO_ERROR)
  20533.                  *pErr = DMGERR_ADVACKTIMEOUT;
  20534.              goto failexit;
  20535.          }
  20536.          if (!AddAdvList(pci->ci.pAdviseList, pXad->pXferInfo->hszItem,
  20537.                  pXad->pXferInfo->usType & (DDE_FACKREQ | DDE_FNODATA),
  20538.                  pXad->pXferInfo->usFmt)) {
  20539.              pXad->state = CONVST_INCOMPLETE;
  20540.              pci->ci.pai->LastError = DMGERR_MEMORY_ERROR;
  20541.              return(FALSE);
  20542.          } else {
  20543.              pXad->state = CONVST_CONNECTED;
  20544.              pci->ci.fs |= ST_ADVISE;
  20545.              return(TRUE);
  20546.          }
  20547.          break;
  20548.  
  20549.      case XTYP_ADVSTOP:
  20550.          if (pXad->state != CONVST_UNADVACKRCVD) {
  20551.              if (*pErr == DMGERR_NO_ERROR)
  20552.                  *pErr = DMGERR_UNADVACKTIMEOUT;
  20553.              goto failexit;
  20554.          }
  20555.          if (!DeleteAdvList(pci->ci.pAdviseList, pXad->pXferInfo->hszItem,
  20556.                  pXad->pXferInfo->usFmt))
  20557.              pci->ci.fs &= ~ST_ADVISE;
  20558.          pXad->state = CONVST_CONNECTED;
  20559.          return(TRUE);
  20560.          break;
  20561.  
  20562.      }
  20563.  
  20564.  failexit:
  20565.      pXad->state = CONVST_INCOMPLETE;
  20566.      return(0);
  20567.  }
  20568.  
  20569.  
  20570.  
  20571.  
  20572.  
  20573.  
  20574.  /*
  20575.   * ----------------------------SERVER SECTION--------------------------------
  20576.   */
  20577.  
  20578.  
  20579.  
  20580.  /***************************** Public  Function ****************************\
  20581.  * MRESULT EXPENTRY ServerWndProc(hwnd, msg, mp1, mp2)
  20582.  * HWND hwnd;
  20583.  * USHORT msg;
  20584.  * MPARAM mp1;
  20585.  * MPARAM mp2;
  20586.  *
  20587.  * DESCRIPTION:
  20588.  *   This processes DDE conversations from the server end.
  20589.  *   It stores internal information and acts much like a state machine.
  20590.  *   If closed, it will automaticly abort any conversation in progress.
  20591.  *   It also maintains an internal list of all items which currently are
  20592.  *   in active ADVISE loops.
  20593.  * PUBDOC START
  20594.  *   These server windows have the feature that a conversation can be
  20595.  *   re-initiated with them by a client.  The Client merely terminates
  20596.  *   the conversation and then re-initiates by using a SendMsg to this
  20597.  *   window.  This allows a client to change the topic of the conversation
  20598.  *   or to pass the conversation on to another client window without
  20599.  *   loosing the server it initiated with.   This is quite useful for
  20600.  *   wild initiates.
  20601.  * PUBDOC END
  20602.  *
  20603.  * History:
  20604.  * 10/18/89 sanfords Added hack to make hszItem==0L when offszItem==offabData.
  20605.  * 1/4/89   sanfords created
  20606.  \***************************************************************************/
  20607.  MRESULT EXPENTRY ServerWndProc(hwnd, msg, mp1, mp2)
  20608.  HWND hwnd;
  20609.  USHORT msg;
  20610.  MPARAM mp1;
  20611.  MPARAM mp2;
  20612.  {
  20613.  #define PDDES ((PDDESTRUCT)mp2)
  20614.      register PSERVERINFO psi;
  20615.      MPARAM mrData;
  20616.      PADVLI pAdviseItem;
  20617.      PSZ pszApp, pszTopic;
  20618.      HSZ hsz;
  20619.      USHORT cchApp, cchTopic;
  20620.      USHORT usType;
  20621.      HDMGDATA hDmgData = 0L;
  20622.      BOOL fResult;
  20623.  
  20624.  
  20625.      psi = (PSERVERINFO)WinQueryWindowULong(hwnd, QWL_USER);
  20626.  
  20627.      switch (msg) {
  20628.      case WM_DDE_REQUEST:
  20629.      case WM_DDE_ACK:
  20630.      case WM_DDE_ADVISE:
  20631.      case WM_DDE_UNADVISE:
  20632.      case WM_DDE_POKE:
  20633.      case WM_DDE_EXECUTE:
  20634.          /*
  20635.           * only respond if this is for us.
  20636.           */
  20637.          if ((HWND)mp1 != psi->ci.hwndPartner || !(psi->ci.fs & ST_CONNECTED))
  20638.              FreeData((PMYDDES)mp2, psi->ci.pai);
  20639.              return(0);
  20640.          }
  20641.      }
  20642.  
  20643.      switch (msg) {
  20644.      case WM_CREATE: {
  20645.              PAPPINFO pai;
  20646.  
  20647.              /*
  20648.               * allocate and initialize the server window info.
  20649.               */
  20650.              pai = GetCurrentAppInfo(FALSE);
  20651.              SemEnter();
  20652.  
  20653.              if (!(psi = (PSERVERINFO)FarAllocMem(pai->hheapApp, sizeof(SERVER
  20654.                  goto LowMem;
  20655.              FillBlock((PBYTE)&psi->ci, sizeof(COMMONINFO), 0);
  20656.              if (!(psi->ci.pAdviseList = CreateLst(pai->hheapApp, sizeof(ADVLI
  20657.                  FarFreeMem(pai->hheapApp, (PBYTE)psi, sizeof(SERVERINFO));
  20658.  LowMem:
  20659.                  pai->LastError = DMGERR_MEMORY_ERROR;
  20660.                  SemLeave();
  20661.                  return(1);          /* abort creation - low memory */
  20662.              }
  20663.              SemLeave();
  20664.              psi->ci.pai = pai;
  20665.              psi->ci.xad.state = CONVST_NULL;
  20666.              WinSetWindowULong(hwnd, QWL_USER, (ULONG)psi);
  20667.          }
  20668.          break;
  20669.  
  20670.      case UMSR_INITIATE:
  20671.          /*
  20672.           * This was sent by the subclassed frame of the server app.
  20673.           * The frame has already queried the server for permission
  20674.           * to create this window.
  20675.           *
  20676.           * If mp2 is NULL, this is a hot server window waiting for
  20677.           * a WM_DDE_INITIATE.
  20678.           */
  20679.  #define pii ((PINITINFO)mp1)
  20680.          IncHszCount(psi->ci.hszServerApp = pii->hszAppName);
  20681.          IncHszCount(psi->ci.hszTopic = pii->hszTopic);
  20682.          psi->ci.hwndPartner = (HWND)mp2;
  20683.          psi->ci.hwndFrame = FindFrame(psi->ci.hwndPartner);
  20684.          psi->ci.cc.fsContext = pii->pCC->fsContext;
  20685.          psi->ci.cc.idCountry = pii->pCC->idCountry;
  20686.          psi->ci.cc.usCodepage = pii->pCC->usCodepage;
  20687.          psi->ci.fs |= ST_CONNECTED;
  20688.          psi->ci.xad.state = CONVST_CONNECTED;
  20689.  
  20690.          SemEnter();
  20691.          pszApp = pszFromHsz(psi->ci.hszServerApp, &cchApp);
  20692.          pszTopic = pszFromHsz(psi->ci.hszTopic, &cchTopic);
  20693.          SemLeave();
  20694.  
  20695.          if (mp2)
  20696.              WinDdeRespond((HWND)mp2, hwnd, pszApp, pszTopic);
  20697.  
  20698.          SemEnter();
  20699.          FarFreeMem(hheapDmg, (PBYTE)pszApp, cchApp);
  20700.          FarFreeMem(hheapDmg, (PBYTE)pszTopic, cchTopic);
  20701.          SemLeave();
  20702.  
  20703.          return(1);
  20704.  #undef pii
  20705.          break;
  20706.  
  20707.      case WM_DDE_INITIATE:
  20708.          /*
  20709.           * This will happen when a client tries to re-initiate a conversation
  20710.           * with this server.  We allow about 10 seconds after termination
  20711.           * for another client to connect specifically with this window.
  20712.           * This allows a client to swap windows on its end of the conversatio
  20713.           */
  20714.  
  20715.          if (psi->ci.xad.state == CONVST_TERMINATED &&
  20716.                  (psi->ci.hszServerApp == GetHsz(PSZAPP(mp2), psi->ci.cc.idCou
  20717.                          psi->ci.cc.usCodepage, FALSE))) {
  20718.  
  20719.              WinStopTimer(DMGHAB, hwnd, TID_SELFDESTRUCT);
  20720.              hsz = psi->ci.hszTopic;
  20721.              psi->ci.hszTopic = GetHsz(PSZTOPIC(mp2), psi->ci.cc.idCountry,
  20722.                      psi->ci.cc.usCodepage, TRUE);
  20723.              FreeHsz(hsz);
  20724.              psi->ci.hwndPartner = (HWND)mp1;
  20725.              psi->ci.hwndFrame = FindFrame(psi->ci.hwndPartner);
  20726.              psi->ci.fs |= ST_CONNECTED;
  20727.              psi->ci.xad.state = CONVST_CONNECTED;
  20728.              if (WinQueryWindowPtr(psi->ci.hwndPartner, QWP_PFNWP) == ClientWn
  20729.                  psi->ci.fs |= ST_INTRADLL;
  20730.              WinDdeRespond((HWND)mp1, hwnd, PSZAPP(mp2), PSZTOPIC(mp2));
  20731.              fResult = TRUE;
  20732.          } else
  20733.              fResult = FALSE;
  20734.  
  20735.          FreeData((PMYDDES)mp2, psi->ci.pai);
  20736.          return(fResult);
  20737.          break;
  20738.  
  20739.      case WM_DDE_TERMINATE:
  20740.          /*
  20741.           * only respond if this is for us.
  20742.           */
  20743.          if ((HWND)mp1 != psi->ci.hwndPartner)
  20744.              break;
  20745.          /* fall through */
  20746.  
  20747.      case UMSR_TERMINATE:
  20748.          /*
  20749.           * terminates any conversation in progress
  20750.           * Note that we keep around all the other conversation data so
  20751.           * a later re-connection is possible.
  20752.           */
  20753.          if (psi->ci.fs & ST_CONNECTED) {
  20754.              psi->ci.fs &= ~ST_CONNECTED;
  20755.              psi->ci.xad.state = CONVST_TERMINATED;
  20756.              if (WinIsWindow(DMGHAB, psi->ci.hwndPartner))
  20757.                  WinDdePostMsg(psi->ci.hwndPartner, hwnd, WM_DDE_TERMINATE, 0L
  20758.          }
  20759.          if (psi->ci.fs & ST_ADVISE) {
  20760.              FlushLst(psi->ci.pAdviseList);
  20761.              psi->ci.fs &= ~ST_ADVISE;
  20762.          }
  20763.          /*
  20764.           * Mr. Phelps, if this window isn't reconnected within 10 odd
  20765.           * seconds, it will self-destruct.  This gives the client time
  20766.           * to reconnect with another client window.  This often happens
  20767.           * with wild initiates.
  20768.           */
  20769.          WinStartTimer(DMGHAB, hwnd, TID_SELFDESTRUCT, 0xa000);
  20770.          break;
  20771.  
  20772.      case WM_TIMER:
  20773.          if (LOUSHORT(mp1) == TID_SELFDESTRUCT && !(psi->ci.fs & ST_CONNECTED)
  20774.              DestroyWindow(hwnd);
  20775.          break;
  20776.  
  20777.      case WM_DESTROY:
  20778.          SemCheckOut();
  20779.          /*
  20780.           * Send ourselves a terminate and free local data.
  20781.           */
  20782.          WinSendMsg(hwnd, UMSR_TERMINATE, 0L, 0L);
  20783.          MakeCallback(psi->ci.pai, hwnd, psi->ci.hszTopic, (HSZ)NULL, 0, XTYP_
  20784.                  0L, 0, 0, psi->ci.hwndPartner);
  20785.          SemEnter();
  20786.          DestroyLst(psi->ci.pAdviseList);
  20787.          FreeHsz(psi->ci.hszServerApp);
  20788.          FreeHsz(psi->ci.hszTopic);
  20789.          FarFreeMem(psi->ci.pai->hheapApp, (PBYTE)psi, sizeof(SERVERINFO));
  20790.          SemLeave();
  20791.          break;
  20792.  
  20793.      case WM_DDE_REQUEST:
  20794.          usType = XTYP_REQUEST;
  20795.          goto Callback;
  20796.  
  20797.      case WM_DDE_EXECUTE:
  20798.          usType = XTYP_EXEC;
  20799.          hDmgData = mp2;
  20800.          goto Callback;
  20801.  
  20802.      case WM_DDE_POKE:
  20803.          usType = XTYP_POKE;
  20804.          hDmgData = mp2;
  20805.          goto Callback;
  20806.  
  20807.      case WM_DDE_ADVISE:
  20808.          usType = XTYP_ADVSTART; /* set ST_ADVISE AFTER app oks advise loop */
  20809.          goto Callback;
  20810.  
  20811.      case WM_DDE_UNADVISE:
  20812.          /*
  20813.           * Terminate the advise now, but notify the server in callback so
  20814.           * messages don't get out of order.
  20815.           */
  20816.          if (!DeleteAdvList(psi->ci.pAdviseList,
  20817.                  GetHszItem(mp2, &psi->ci.cc, FALSE),
  20818.                  PDDES->usFormat))
  20819.              psi->ci.fs &= ~ST_ADVISE;
  20820.          usType = XTYP_ADVSTOP;
  20821.          goto Callback;
  20822.  
  20823.      case WM_DDE_ACK:
  20824.          /*
  20825.           * This is an ack in response to the FACKREQ bit being set.
  20826.           * See if this refers to one of the advise loops.
  20827.           */
  20828.          if ((pAdviseItem = FindAdvList(psi->ci.pAdviseList,
  20829.                  GetHszItem(mp2, &psi->ci.cc, FALSE),
  20830.                  PDDES->usFormat)) &&
  20831.                  (pAdviseItem->fsStatus & DDE_FACKREQ)) {
  20832.              /*
  20833.               * Update advise loop status - no longer waiting for an ack.
  20834.               */
  20835.              pAdviseItem->fsStatus &= ~ADVST_WAITING;
  20836.              if (pAdviseItem->fsStatus & ADVST_CHANGED) {
  20837.                  pAdviseItem->fsStatus |= ADVST_POSTED;
  20838.                  /*
  20839.                   * The client is out of date.  Send the data
  20840.                   * again (simulate a post advise call).
  20841.                   * Don't bother the server with ACK info.
  20842.                   */
  20843.                  MakeCallback(psi->ci.pai, (HCONV)hwnd, psi->ci.hszTopic,
  20844.                          pAdviseItem->hszItem,
  20845.                          pAdviseItem->usFmt, XTYP_ADVREQ,
  20846.                          0L, UMSR_POSTADVISE,
  20847.                          pAdviseItem->fsStatus & ~DDE_FRESERVED,
  20848.                          psi->ci.hwndPartner);
  20849.                  FreeData((PMYDDES)mp2, psi->ci.pai);
  20850.                  return(0);
  20851.              }
  20852.          }
  20853.          usType = XTYP_ACK;
  20854.          hDmgData = PDDES->fsStatus;
  20855.  
  20856.  Callback:
  20857.          MakeCallback(psi->ci.pai, (HCONV)hwnd, psi->ci.hszTopic,
  20858.  #if 0
  20859.                  /*
  20860.                   * hack for EXCEL which makes its items and data equal for
  20861.                   * execute acks which SHOULD use NULL as the item name.
  20862.                   */
  20863.                  (PDDES->offszItemName == PDDES->offabData) ?
  20864.                      0L :
  20865.  #endif
  20866.                  GetHszItem((PMYDDES)mp2, &psi->ci.cc, TRUE),
  20867.                  PDDES->usFormat, usType,
  20868.                  hDmgData, msg, PDDES->fsStatus,
  20869.                  psi->ci.hwndPartner);
  20870.          /*
  20871.           * now free the incomming selector IF it wasn't passed on to
  20872.           * MakeCallback as hDmgData.
  20873.           */
  20874.          if (hDmgData != mp2)
  20875.              FreeData((PMYDDES)mp2, psi->ci.pai);
  20876.          break;
  20877.  
  20878.      case UMSR_POSTADVISE:
  20879.          /*
  20880.           * This message came from DdePostAdvise()
  20881.           *
  20882.           * Advise loops are tricky because of the desireable FACKREQ feature
  20883.           * of DDE.  The advise loop list holds information in its fsStatus
  20884.           * field to maintain the state of the advise loop.
  20885.           *
  20886.           * if the ADVST_POSTED bit is set, it means that the server already
  20887.           * has an ADVREQ message in its callback queue.  This prevents
  20888.           * unnecessary ADVREQ messages from getting thrown into the callback
  20889.           * queue.
  20890.           *
  20891.           * if the ADVST_WAITING bit is set, the server is still waiting for
  20892.           * the client to give it the go-ahead for more data with an
  20893.           * ACK message on this item. (FACKREQ is set)  Without a go-ahead,
  20894.           * the server will not send any more advise data to the client but
  20895.           * will instead set the ADVST_CHANGED bit which will cause another
  20896.           * WM_DDE_DATA message to be sent to the client as soon as the
  20897.           * go-ahead ACK is received.  This keeps the client up to date
  20898.           * but never overloads it.
  20899.           */
  20900.  
  20901.          if (!(psi->ci.fs & ST_ADVISE) ||
  20902.                  !(pAdviseItem = FindAdvList(psi->ci.pAdviseList, (HSZ)mp1, 0)
  20903.              break;
  20904.  
  20905.          do {
  20906.              /*
  20907.               * for each format for this item that has an advise loop:
  20908.               */
  20909.              if (pAdviseItem->fsStatus & ADVST_POSTED)
  20910.                  continue;
  20911.  
  20912.              if ((pAdviseItem->fsStatus & DDE_FACKREQ) &&
  20913.                      (pAdviseItem->fsStatus & ADVST_WAITING)) {
  20914.                  /*
  20915.                   * if the client has not yet finished with the last data
  20916.                   * we gave him, just update the advise loop status
  20917.                   * instead of sending data now.
  20918.                   */
  20919.                  pAdviseItem->fsStatus |= ADVST_CHANGED;
  20920.                  continue;
  20921.              }
  20922.              if (pAdviseItem->fsStatus & DDE_FNODATA) {
  20923.                  /*
  20924.                   * In the nodata case, we don't bother the server.  Just
  20925.                   * pass the client an apropriate DATA message.
  20926.                   */
  20927.                  MyDdePostMsg(psi->ci.hwndPartner, hwnd, WM_DDE_DATA,
  20928.                          (PMYDDES)AllocDDESel(pAdviseItem->fsStatus & ~(DDE_FN
  20929.                          pAdviseItem->usFmt, (HSZ)mp1, 0L, 0),
  20930.                          psi->ci.pai, MDPM_FREEHDATA);
  20931.                  continue;
  20932.              }
  20933.              /*
  20934.               * Otherwise, lets get the data from the server.
  20935.               */
  20936.              pAdviseItem->fsStatus |= ADVST_POSTED;
  20937.              MakeCallback(psi->ci.pai, (HCONV)hwnd, psi->ci.hszTopic,
  20938.                      (HSZ)mp1, pAdviseItem->usFmt, XTYP_ADVREQ,
  20939.                      0, UMSR_POSTADVISE,
  20940.                      pAdviseItem->fsStatus & (DDE_FACKREQ | DDE_FNODATA),
  20941.                      psi->ci.hwndPartner);
  20942.          } while (pAdviseItem = FindNextAdv(pAdviseItem, (HSZ)mp1));
  20943.          break;
  20944.  
  20945.      case UM_QUERY:
  20946.          /*
  20947.           * LOUSHORT(mp1) = info index.
  20948.           * mp2 = pData.     If pData==0, return data else copy into pData.
  20949.           */
  20950.          switch (LOUSHORT(mp1)) {
  20951.          case Q_STATUS:
  20952.               mrData = (MRESULT)psi->ci.fs;
  20953.               break;
  20954.  
  20955.          case Q_CLIENT:
  20956.               mrData = FALSE;
  20957.               break;
  20958.  
  20959.          case Q_APPINFO:
  20960.               mrData = psi->ci.pai;
  20961.               break;
  20962.  
  20963.          case Q_APPNAME:
  20964.               mrData = psi->ci.hszServerApp;
  20965.               break;
  20966.  
  20967.          case Q_TOPIC:
  20968.               mrData = psi->ci.hszTopic;
  20969.               break;
  20970.  
  20971.          case Q_ALL:
  20972.               mrData = (MRESULT)(SERVERINFO FAR *)psi;
  20973.               break;
  20974.          }
  20975.          if (mp2 == 0)
  20976.              return(mrData);
  20977.          else
  20978.              *(MRESULT FAR *)mp2 = mrData;
  20979.          return(1);
  20980.          break;
  20981.  
  20982.      default:
  20983.          return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  20984.          break;
  20985.      }
  20986.      return(0);
  20987.  #undef PDDES
  20988.  }
  20989.  
  20990.  
  20991.  
  20992.  
  20993.  /*
  20994.   * This assumes hwnd is a DDE window.  It tries to locate the proper
  20995.   * top-level frame window that this window is associated with useing
  20996.   * process and thread IDs.
  20997.   */
  20998.  HWND FindFrame(
  20999.  HWND hwnd)
  21000.  {
  21001.      PID pid, pidFrame;
  21002.      TID tid, tidFrame;
  21003.      HWND hwndMaybe = NULL;
  21004.      HWND hwndBetter = NULL;
  21005.      HWND hwndFrame;
  21006.      HENUM hEnum;
  21007.      ULONG ul;
  21008.  
  21009.      WinQueryWindowProcess(hwnd, &pid, &tid);
  21010.      hEnum = WinBeginEnumWindows(HWND_DESKTOP);
  21011.      while (hwndFrame = WinGetNextWindow(hEnum)) {
  21012.          /*
  21013.           * for all top level windows ...
  21014.           */
  21015.          ul = (ULONG)WinSendMsg(hwndFrame, WM_QUERYFRAMEINFO, 0L, 0L);
  21016.          if (FI_FRAME & ul) {
  21017.              /*
  21018.               * that are frames ...
  21019.               */
  21020.              WinQueryWindowProcess(hwndFrame, &pidFrame, &tidFrame);
  21021.              if (pidFrame == pid) {
  21022.                  /*
  21023.                   * in this process - maybe - ...
  21024.                   */
  21025.                  hwndMaybe = hwndFrame;
  21026.                  if (tidFrame == tid) {
  21027.                      /*
  21028.                       * in this thread - better - ...
  21029.                       */
  21030.                      hwndBetter = hwndFrame;
  21031.                      if (WinQueryWindowPtr(hwndFrame, QWP_PFNWP) ==
  21032.                              subframeWndProc) {
  21033.                          /*
  21034.                           * that are subclassed by us - certainly!
  21035.                           */
  21036.                          hwndBetter = hwndFrame;
  21037.                          break;
  21038.                      }
  21039.                  }
  21040.              }
  21041.          }
  21042.      }
  21043.      WinEndEnumWindows(hEnum);
  21044.      return(hwndBetter ? hwndBetter : hwndMaybe);
  21045.  }
  21046.  
  21047.  
  21048.  
  21049.  
  21050.  /***************************** Private Function ****************************\
  21051.  * This routine handles server message replys.  This may have been called
  21052.  * immediately in the case of enabled callbacks, or may have been called
  21053.  * via DdeEnableCallback in which case the server action has been
  21054.  * delayed.  QReply is responsible for freeing the pddes given as well as
  21055.  * the pcbi->hDmgData and pcbi->hszItem.
  21056.  *
  21057.  * History:
  21058.  *   Created     9/12/89    Sanfords
  21059.  *   6/12/90 sanfords    Added checks for HDATA ownership.
  21060.  \***************************************************************************/
  21061.  void QReply(pcbi, pddes)
  21062.  PCBLI pcbi;
  21063.  PDDESTRUCT pddes;   /* hDataRet */
  21064.  {
  21065.      PSERVERINFO psi;
  21066.      PADVLI pAdviseItem;
  21067.      USHORT fsStatus, msg;
  21068.  
  21069.      if ((pcbi->usType & XCLASS_MASK) == XCLASS_NOTIFICATION)
  21070.          return;
  21071.  
  21072.      SemCheckOut();
  21073.      psi = WinSendMsg(pcbi->hConv, UM_QUERY, (MPARAM)Q_ALL, 0L);
  21074.  
  21075.      switch (pcbi->msg) {
  21076.      case UMSR_POSTADVISE:
  21077.          /*
  21078.           * The NODATA case never gets here.
  21079.           */
  21080.          if ((psi) &&
  21081.                  (pAdviseItem = FindAdvList(psi->ci.pAdviseList, pcbi->hszItem
  21082.                  pcbi->usFmt))) {
  21083.              pAdviseItem->fsStatus &= ~ADVST_POSTED;
  21084.              if (pddes) {
  21085.                  pAdviseItem->fsStatus &= ~ADVST_CHANGED;
  21086.                  MyDdePostMsg(pcbi->hConvPartner, pcbi->hConv, WM_DDE_DATA,
  21087.                          (PMYDDES)pddes, psi->ci.pai, MDPM_FREEHDATA);
  21088.                  if (pAdviseItem->fsStatus & DDE_FACKREQ)
  21089.                      pAdviseItem->fsStatus |= ADVST_WAITING;
  21090.              }
  21091.          }
  21092.          break;
  21093.  
  21094.      case WM_DDE_REQUEST:
  21095.          if (pddes) {
  21096.              pddes->fsStatus = (pcbi->fsStatus & DDE_FACKREQ) | DDE_FRESPONSE;
  21097.              msg = WM_DDE_DATA;
  21098.          } else {
  21099.              /*
  21100.               * send a -ACK
  21101.               */
  21102.              pddes = AllocDDESel(((USHORT)pddes & DDE_FAPPSTATUS) |
  21103.                      ((USHORT)pddes & DDE_FBUSY ? DDE_FBUSY : DDE_NOTPROCESSED
  21104.                      pcbi->usFmt, pcbi->hszItem, 0L, NULL);
  21105.              msg = WM_DDE_ACK;
  21106.          }
  21107.          MyDdePostMsg(pcbi->hConvPartner, pcbi->hConv, msg, (PMYDDES)pddes,
  21108.                  psi->ci.pai, MDPM_FREEHDATA);
  21109.          break;
  21110.  
  21111.      case WM_DDE_POKE:
  21112.      case WM_DDE_EXECUTE:
  21113.          /*
  21114.           * pddes is supposed to be the proper DDE_ constants to return.
  21115.           * we just stick them in the given pddes (hDmgData) and return
  21116.           * it as an ACK.  This frees pcbi->hDmgData in the process.
  21117.           */
  21118.          ((PDDESTRUCT)pcbi->hDmgData)->fsStatus =
  21119.                  (USHORT)pddes & ~DDE_FRESERVED;
  21120.          MyDdePostMsg(pcbi->hConvPartner, pcbi->hConv, WM_DDE_ACK,
  21121.                  (PMYDDES)pcbi->hDmgData, psi->ci.pai, MDPM_FREEHDATA);
  21122.          break;
  21123.  
  21124.      case WM_DDE_ADVISE:
  21125.          /*
  21126.           * pddes is fStartAdvise
  21127.           * If DDE_FACK, we add the item to the advise loop
  21128.           * list and +ACK else we -ACK.
  21129.           */
  21130.          if ((BOOL)pddes) {
  21131.              psi = (PSERVERINFO)WinQueryWindowULong(pcbi->hConv, QWL_USER);
  21132.              if (AddAdvList(psi->ci.pAdviseList, pcbi->hszItem,
  21133.                      pcbi->fsStatus & (DDE_FNODATA | DDE_FACKREQ),
  21134.                      pcbi->usFmt) == NULL) {
  21135.                  psi->ci.pai->LastError = DMGERR_MEMORY_ERROR;
  21136.                  fsStatus = DDE_NOTPROCESSED;
  21137.              } else {
  21138.                  psi->ci.fs |= ST_ADVISE;
  21139.                  fsStatus = DDE_FACK;
  21140.              }
  21141.          } else {
  21142.              fsStatus = DDE_NOTPROCESSED;
  21143.          }
  21144.          goto AckBack;
  21145.          break;
  21146.  
  21147.      case WM_DDE_UNADVISE:
  21148.          fsStatus = DDE_FACK;
  21149.          goto AckBack;
  21150.          break;
  21151.  
  21152.      case WM_DDE_DATA:
  21153.          /*
  21154.           * must be an advise data item for the CLIENT or maybe some requested
  21155.           * data mistakenly sent here due to the client queue being flushed.
  21156.           * pddes is fsStatus.
  21157.           *
  21158.           * send an ack back if requested.
  21159.           */
  21160.          if (pcbi->fsStatus & DDE_FACKREQ) {
  21161.              /*
  21162.               * Clean up the status incase the app is messed up.
  21163.               */
  21164.              fsStatus = (USHORT)pddes & ~DDE_FRESERVED;
  21165.              if (fsStatus & (DDE_NOTPROCESSED | DDE_FBUSY))
  21166.                  fsStatus &= ~DDE_FACK;
  21167.  AckBack:
  21168.              MyDdePostMsg(pcbi->hConvPartner, pcbi->hConv, WM_DDE_ACK,
  21169.                  (PMYDDES)AllocDDESel(fsStatus, pcbi->usFmt, pcbi->hszItem, 0L
  21170.                  psi->ci.pai, MDPM_FREEHDATA);
  21171.          }
  21172.          break;
  21173.      }
  21174.  }
  21175.  
  21176.  
  21177.  
  21178.  /*
  21179.   * ----------------FRAME SECTION------------------
  21180.   *
  21181.   * A frame window exists on behalf of every registered thread.  It
  21182.   * handles conversation initiation and therefore issues callbacks
  21183.   * to the server app as needed to notify or query the server app.
  21184.   * The callback queue is always bypassed for these synchronous
  21185.   * events.
  21186.   */
  21187.  
  21188.  /***************************** Private Function ****************************\
  21189.  * MRESULT EXPENTRY subframeWndProc(hwnd, msg, mp1, mp2)
  21190.  * HWND hwnd;
  21191.  * USHORT msg;
  21192.  * MPARAM mp1;
  21193.  * MPARAM mp2;
  21194.  *
  21195.  * This routine takes care of setting up server windows as needed to respond
  21196.  * to incomming WM_DDE_INTIIATE messages.  It is subclassed from the top
  21197.  * level frame of the server application.
  21198.  *
  21199.  * History:  created 12/20/88    sanfords
  21200.  \***************************************************************************/
  21201.  MRESULT EXPENTRY subframeWndProc(hwnd, msg, mp1, mp2)
  21202.  HWND hwnd;
  21203.  USHORT msg;
  21204.  MPARAM mp1;
  21205.  MPARAM mp2;
  21206.  {
  21207.      PAPPINFO pai;
  21208.  
  21209.      pai = GetCurrentAppInfo(FALSE);
  21210.  
  21211.      switch (msg) {
  21212.      case UM_REGISTER:
  21213.      case UM_UNREGISTER:
  21214.          /*
  21215.           * we pass notification messages through this proc so we can make the
  21216.           * xfer call within the correct thread's context.
  21217.           */
  21218.          MakeCallback(pai, (HCONV)0, (HSZ)0, (HSZ)mp1, 0,
  21219.                  msg == UM_REGISTER ? XTYP_REGISTER : XTYP_UNREGISTER,
  21220.                  (HDMGDATA)mp2, msg, 0, 0L);
  21221.          return(0);
  21222.          break;
  21223.  
  21224.      case WM_DDE_INITIATE:
  21225.          FrameInitConv((HWND)mp1, (PDDEINIT)mp2);
  21226.          FreeData((PMYDDES)mp2, pai);
  21227.          break;
  21228.  
  21229.      default:
  21230.          return((*lpfnFrameWndProc)(hwnd, msg, mp1, mp2));
  21231.          break;
  21232.      }
  21233.  }
  21234.  
  21235.  
  21236.  
  21237.  void FrameInitConv(hwndClient, pddei)
  21238.  HWND hwndClient;
  21239.  PDDEINIT pddei;
  21240.  {
  21241.      PAPPINFO pai, paiClient;
  21242.      INITINFO ii;
  21243.      HSZPAIR hp[2];
  21244.      PHSZPAIR php;
  21245.      HSZ hsz = 0;
  21246.      HDMGDATA hDataCC;
  21247.      PDDESTRUCT pddes;
  21248.      HWND hwndServer;
  21249.      CONVCONTEXT cc;
  21250.      BOOL fWild;
  21251.  
  21252.      if (!CheckSel(SELECTOROF(pddei))) {
  21253.          AssertF(FALSE, "Invalid DDEINIT selector");
  21254.          return;
  21255.      }
  21256.  
  21257.      SemCheckOut();
  21258.  
  21259.      pai = GetCurrentAppInfo(FALSE);
  21260.      /*
  21261.       * If we are filtering and no app names are registered, quit.
  21262.       */
  21263.      if ((pai->afCmd & DMGCMD_FILTERINITS) &&
  21264.              QPileItemCount(pai->pAppNamePile) == 0)
  21265.          return;
  21266.  
  21267.      /*
  21268.       * filter out inits from ourselves and other agents (if we are an agent)
  21269.       */
  21270.      if (WinQueryWindowPtr(hwndClient, QWP_PFNWP) == ClientWndProc) {
  21271.          paiClient = WinSendMsg(hwndClient, UM_QUERY, (MPARAM)Q_APPINFO, 0L);
  21272.          if (paiClient == pai)
  21273.              return;
  21274.  
  21275.          if ((pai->afCmd & DMGCMD_AGENT) && (paiClient->afCmd & DMGCMD_AGENT))
  21276.              return;
  21277.      }
  21278.  
  21279.      /*
  21280.       * make sure ii.pCC is set up right.
  21281.       */
  21282.      if (pddei->cb >= sizeof(DDEINIT) && pddei->offConvContext) {
  21283.          /*
  21284.           * new dde init structure!
  21285.           */
  21286.          ii.pCC = DDEI_PCONVCONTEXT(pddei);
  21287.      } else {
  21288.          ii.pCC = &cc;
  21289.          cc.cb = sizeof(CONVCONTEXT);
  21290.          cc.idCountry = syscc.country;
  21291.          cc.usCodepage = syscc.codepage;
  21292.          cc.fsContext = 0;
  21293.      }
  21294.  
  21295.  
  21296.      hp[0].hszApp = GetHsz(PSZAPP(pddei), ii.pCC->idCountry,
  21297.              ii.pCC->usCodepage, TRUE);
  21298.  
  21299.      /*
  21300.       * filter out unwanted app names.
  21301.       */
  21302.      if (hp[0].hszApp && (pai->afCmd & DMGCMD_FILTERINITS) &&
  21303.              !FindPileItem(pai->pAppNamePile, CmppHsz, (PBYTE)&hp[0].hszApp, 0
  21304.          FreeHsz(hp[0].hszApp);
  21305.          return;
  21306.      }
  21307.  
  21308.      hp[0].hszTopic = GetHsz(PSZTOPIC(pddei), ii.pCC->idCountry,
  21309.              ii.pCC->usCodepage, TRUE);
  21310.  
  21311.      hp[1].hszApp = hp[1].hszTopic = 0L;
  21312.  
  21313.      fWild = (hp[0].hszApp == 0L || hp[0].hszTopic == 0);
  21314.  
  21315.      hDataCC = PutData((PBYTE)ii.pCC, (ULONG)sizeof(CONVCONTEXT), 0L, (HSZ)NUL
  21316.              0, 0, pai);
  21317.  
  21318.      if (hDataCC == NULL)
  21319.          goto CheckOut;
  21320.  
  21321.      pddes = (PDDESTRUCT)DoCallback(pai, NULL, hp[0].hszTopic,
  21322.                      hp[0].hszApp, 0, (fWild ? XTYP_WILDINIT : XTYP_INIT),
  21323.                      hDataCC);
  21324.  
  21325.      if (pddes == NULL)
  21326.          goto CheckOut;
  21327.  
  21328.      FindPileItem(pai->pHDataPile, CmpULONG, (PBYTE)&hDataCC, FPI_DELETE);
  21329.      DosFreeSeg(SELECTOROF(hDataCC));
  21330.  
  21331.      if (fWild) {
  21332.          php = (PHSZPAIR)DDES_PABDATA(pddes);
  21333.      } else {
  21334.          php = &hp[0];
  21335.          pddes = NULL;
  21336.      }
  21337.  
  21338.      /*
  21339.       * now php points to a 0 terminated list of hszpairs to respond to.
  21340.       */
  21341.      SemEnter();
  21342.      while (QuerylatomLength((LATOM)php->hszApp) &&
  21343.              QuerylatomLength((LATOM)php->hszTopic)) {
  21344.          SemLeave();
  21345.          if ((hwndServer = CreateServerWindow(pai, php->hszTopic)) == 0)
  21346.              break;
  21347.          /*
  21348.           * have the server respond
  21349.           */
  21350.          ii.hszAppName = php->hszApp;
  21351.          ii.hszTopic = php->hszTopic;
  21352.          WinSendMsg(hwndServer, UMSR_INITIATE, (MPARAM)&ii, hwndClient);
  21353.  
  21354.          /*
  21355.           * confirm initialization to server app
  21356.           */
  21357.          DoCallback(pai, (HCONV)hwndServer, php->hszTopic, php->hszApp,
  21358.                  0, XTYP_INIT_CONFIRM, 0L);
  21359.  
  21360.          php++;
  21361.          SemEnter();
  21362.      }
  21363.      SemLeave();
  21364.      SemCheckOut();
  21365.  CheckOut:
  21366.      FreeHsz(hp[0].hszApp);
  21367.      FreeHsz(hp[0].hszTopic);
  21368.      if (fWild)
  21369.          FreeData((PMYDDES)pddes, pai);
  21370.  }
  21371.  
  21372.  HWND CreateServerWindow(
  21373.  PAPPINFO pai,
  21374.  HSZ hszTopic)
  21375.  {
  21376.      HWND hwndTSvr, hwndServer;
  21377.  
  21378.      SemCheckOut();
  21379.      /*
  21380.       * locate or make a Topic server window...
  21381.       */
  21382.      if ((hwndTSvr =
  21383.              HwndFromHsz(hszTopic, pai->pSvrTopicList)) == 0) {
  21384.          /*
  21385.           * NO - make one.
  21386.           */
  21387.          if ((hwndTSvr = WinCreateWindow(pai->hwndDmg, SZDEFCLASS, "", 0L,
  21388.                  0, 0, 0, 0, (HWND)NULL, HWND_BOTTOM, WID_SVRTOPIC,
  21389.                  0L, 0L)) == 0L) {
  21390.              pai->LastError = DMGERR_PMWIN_ERROR;
  21391.              return(NULL);
  21392.          }
  21393.          AddHwndHszList(hszTopic, hwndTSvr, pai->pSvrTopicList);
  21394.      }
  21395.  
  21396.      /*
  21397.       * Create the server window
  21398.       */
  21399.      if ((hwndServer = WinCreateWindow(hwndTSvr, SZSERVERCLASS, "", 0L,
  21400.              0, 0, 0, 0, (HWND)NULL, HWND_BOTTOM, WID_SERVER, 0L, 0L)) == 0L)
  21401.          pai->LastError = DMGERR_PMWIN_ERROR;
  21402.          return(NULL);
  21403.      }
  21404.      return(hwndServer);
  21405.  }
  21406.  
  21407.  /*
  21408.   * main application window - parent of all others in app.
  21409.   *
  21410.   * 6/12/90 sanfords     Fixed semaphore bug
  21411.   */
  21412.  MRESULT EXPENTRY DmgWndProc(hwnd, msg, mp1, mp2)
  21413.  HWND hwnd;
  21414.  USHORT msg;
  21415.  MPARAM mp1;
  21416.  MPARAM mp2;
  21417.  {
  21418.  #define pai ((PAPPINFO)mp1)
  21419.      PCBLI pli, pliNext;
  21420.      BOOL fException;
  21421.      HDMGDATA hDataRet;
  21422.  
  21423.      hwnd;
  21424.      mp2;
  21425.  
  21426.      switch (msg) {
  21427.      case UM_CHECKCBQ:
  21428.          /*
  21429.           * We consider everything to be blocked if we are in a client
  21430.           * transfer modal loop.   This prevents recursive timeout
  21431.           * calls.
  21432.           */
  21433.          if (pai->hwndTimer)
  21434.              return(0);
  21435.  
  21436.          /*
  21437.           * This is where we actually do callbacks.  We do them via this
  21438.           * window proc so that we can asynchronously institute callbacks
  21439.           * via a PostMsg().
  21440.           */
  21441.          SemCheckOut();
  21442.          SemEnter();
  21443.          /*
  21444.           * process all enabled conversation callbacks.
  21445.           */
  21446.          for (pli = (PCBLI)pai->plstCB->pItemFirst; pli; pli = (PCBLI)pliNext)
  21447.              pliNext = (PCBLI)pli->next;
  21448.              fException = FindLstItem(pai->plstCBExceptions, CmpULONG, (PLITEM
  21449.                      == NULL ? FALSE : TRUE;
  21450.              if (fException == pai->fEnableCB)
  21451.                  continue; /* blocked */
  21452.  
  21453.              pai->cInCallback++;
  21454.              SemLeave();
  21455.              /*
  21456.               * make the actual callback here.
  21457.               */
  21458.              hDataRet = DoCallback(pai, pli->hConv, pli->hszTopic,
  21459.                      pli->hszItem, pli->usFmt, pli->usType, pli->hDmgData);
  21460.              SemEnter();
  21461.              if (pai->cInCallback > 0)   /* test incase exlst processing messe
  21462.                  pai->cInCallback--;
  21463.  
  21464.              /*
  21465.               * If the callback resulted in a BLOCK, disable this conversation
  21466.               */
  21467.              if (hDataRet == CBR_BLOCK && !(pli->usType & XTYPF_NOBLOCK)) {
  21468.                  SemLeave();
  21469.                  DdeEnableCallback(pli->hConv, FALSE);
  21470.                  SemEnter();
  21471.                  continue;
  21472.              } else {
  21473.                  /*
  21474.                   * otherwise finish processing the callback.
  21475.                   */
  21476.                  if (WinIsWindow(DMGHAB, pli->hConvPartner)) {
  21477.                      SemLeave();
  21478.                      QReply(pli, (PDDESTRUCT)hDataRet);
  21479.                      SemEnter();
  21480.                  }
  21481.                  RemoveLstItem(pai->plstCB, (PLITEM)pli);
  21482.              }
  21483.          }
  21484.          SemLeave();
  21485.          return(0);
  21486.          break;
  21487.  
  21488.      default:
  21489.          WinDefWindowProc(hwnd, msg, mp1, mp2);
  21490.          break;
  21491.      }
  21492.  #undef pai
  21493.  }
  21494.  
  21495.  
  21496.  HDMGDATA DoCallback(
  21497.  PAPPINFO pai,
  21498.  HCONV hConv,
  21499.  HSZ hszTopic,
  21500.  HSZ hszItem,
  21501.  USHORT usFmt,
  21502.  USHORT usType,
  21503.  HDMGDATA hDmgData)
  21504.  {
  21505.      HDMGDATA hDataRet;
  21506.  
  21507.      AssertF(IncHszCount(hszTopic) && FreeHsz(hszTopic), "Bad hszTopic on call
  21508.      AssertF(IncHszCount(hszItem) && FreeHsz(hszItem), "Bad hszItem on callbac
  21509.  
  21510.      if (usType & XCLASS_DATAIN) {
  21511.          AssertF(CheckSel(SELECTOROF(hDmgData)), "invalid callback data handle
  21512.          ((PMYDDES)hDmgData)->fs |= HDATA_READONLY;
  21513.      }
  21514.  
  21515.  #ifdef CRUISER
  21516.      if (pai->afCmd & DMGCMD_32BIT)
  21517.          hDataRet = ThkCallback(hConv, hszTopic, hszItem, usFmt, usType, hDmgD
  21518.                  pai->pfnCallback);
  21519.      else
  21520.  #endif
  21521.          hDataRet = (*pai->pfnCallback)(hConv, hszTopic, hszItem, usFmt, usTyp
  21522.                  hDmgData);
  21523.  
  21524.      if (usType & XCLASS_DATA && CheckSel(SELECTOROF(hDataRet)) > sizeof(MYDDE
  21525.              ((PMYDDES)hDataRet)->magic == MYDDESMAGIC) {
  21526.          if (((PMYDDES)hDataRet)->pai != pai) {
  21527.              AssertF(FALSE, "hData from callback not created by same thread");
  21528.              pai->LastError = DMGERR_DLL_USAGE;
  21529.              hDataRet = NULL;
  21530.          }
  21531.      }
  21532.      return(hDataRet);
  21533.  }
  21534.  
  21535.  
  21536.  
  21537.  
  21538.  EA.C
  21539.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\STOCK\EA.C
  21540.  
  21541.  /***        ea.c - layer for EA support
  21542.   *
  21543.   *        Author:
  21544.   *            Benjamin W. Slivka
  21545.   *            (c) 1990
  21546.   *            Microsoft Corporation
  21547.   *
  21548.   *        History:
  21549.   *            08-Feb-1990 bens        Initial version (Subset from EA.EXE sou
  21550.   *            02-May-1990 bens        Added SetEAValue (copied from ea.exe)
  21551.   *            01-Jun-1990 bens        Support binary EAs
  21552.   */
  21553.  
  21554.  #define INCL_DOSERRORS
  21555.  #define INCL_DOSFILEMGR
  21556.  #define INCL_NOPM
  21557.  
  21558.  #include <os2.h>
  21559.  
  21560.  #include <ctype.h>
  21561.  #include <stdio.h>
  21562.  #include <stdlib.h>
  21563.  #include <string.h>
  21564.  #include <memory.h>
  21565.  
  21566.  #include "ea.h"
  21567.  #include "mem.h"
  21568.  
  21569.  
  21570.  #ifdef CHECKASSERTS
  21571.  #define dbg(a)        a
  21572.  #else
  21573.  #define dbg(a)
  21574.  #endif
  21575.  
  21576.  // Buffer sizes for EA API calls
  21577.  #define CB_GEAL       400                // Enough for one GEA in list
  21578.  #define CB_FEAL      2000                // Enough for large file list
  21579.  
  21580.  
  21581.  char *            TranslateValue(char *pbValue,USHORT cbValue,USHORT *pcbValu
  21582.  
  21583.  
  21584.  /***        EAQueryValue - Get text EA value from file
  21585.   *
  21586.   *        Entry
  21587.   *            pszFile - File path
  21588.   *            pszName - EA name
  21589.   *            pcbValue - USHORT to receive value length
  21590.   *
  21591.   *        Exit-Success
  21592.   *            returns non-zero pointer to value; Caller must free this!
  21593.   *                If value is ASCII
  21594.   *                    *pcbValue == 0;
  21595.   *                If value is BINARY
  21596.   *                    *pcbValue == length of value;
  21597.   *
  21598.   *        Exit-Failure
  21599.   *            returns NULL
  21600.   */
  21601.  char *EAQueryValue(char *pszFile,char *pszName,USHORT *pcbValue)
  21602.  {
  21603.      USHORT        cb;
  21604.      EAOP        eaop;
  21605.      FEA *        pfea;
  21606.      FEA *        pfeaEnd;
  21607.      FEALIST *        pFEAList;
  21608.      GEA *        pgea;
  21609.      GEALIST *        pGEAList;
  21610.      char *        psz;
  21611.      char *        pszValue;
  21612.      USHORT        rc;
  21613.  
  21614.      //
  21615.      // Alloc GEAList and FEAList
  21616.      //
  21617.      pGEAList = MemAlloc(CB_GEAL);
  21618.      if (pGEAList == NULL) {
  21619.          return NULL;
  21620.      }
  21621.  
  21622.      pFEAList = MemAlloc(CB_FEAL);
  21623.      if (pFEAList == NULL) {
  21624.          MemFree(pGEAList);
  21625.          return NULL;
  21626.      }
  21627.  
  21628.      // Build GEA List with one GEA
  21629.  
  21630.      pgea = pGEAList->list;                // Point at first GEA
  21631.      cb = strlen(pszName);
  21632.      pgea->cbName = (UCHAR)cb;                // Set length
  21633.      memcpy(pgea->szName,pszName,cb+1);        // Copy name and NUL
  21634.      pgea = (GEA *)((char *)pgea + cb + sizeof(GEA));
  21635.      pGEAList->cbList = (char *)pgea - (char *)pGEAList; // Set buffer size
  21636.  
  21637.      // Get attribute value
  21638.  
  21639.      pFEAList->cbList = CB_FEAL;         // Set size of FEA list
  21640.      eaop.fpGEAList = pGEAList;
  21641.      eaop.fpFEAList = pFEAList;
  21642.  
  21643.      rc = DosQPathInfo(pszFile,                // File path
  21644.                        FIL_QUERYEASFROMLIST, // info level
  21645.                        (PBYTE)&eaop,        // EAOP structure
  21646.                        sizeof(eaop),        // Size of EAOP
  21647.                        0L);                // Reserved
  21648.      pfea = (FEA *)pFEAList->list;        // Point at FEA
  21649.  
  21650.      //        NOTE: DosQPathInfo only fails if there is an inconsistency in
  21651.      //              one of its parameters.  It DOES NOT fail if the EA is
  21652.      //              not present.  Rather, on a file system that does not
  21653.      //              support EAs, it appears to return pFEAList->cbList ==
  21654.      //              sizeof(pFEAList->cbList), indicating no FEAs are present.
  21655.      //              If the file system *does* support EAs, but the particular
  21656.      //              EA is not present, pFEA->cbValue == 0.
  21657.  
  21658.      if ((rc == 0) &&                        // Call succeeded,...
  21659.          ((pFEAList->cbList) > sizeof(pFEAList->cbList)) && // FEA is there,..
  21660.          (pfea->cbValue > 0)) {                // and file has EA value!
  21661.          // Parse EA value
  21662.          cb = pfea->cbName;
  21663.          psz = (char *)pfea + sizeof(FEA); // Point at name
  21664.          pszValue = psz + cb + 1;        // Point at value
  21665.          psz = TranslateValue(pszValue,pfea->cbValue,pcbValue);
  21666.      }
  21667.      else
  21668.         psz = NULL;                        // EA not present, or too big
  21669.  
  21670.      MemFree(pFEAList);
  21671.      MemFree(pGEAList);
  21672.      return psz;
  21673.  }
  21674.  
  21675.  
  21676.  /***        TranslateValue - produce printable representation of EA value
  21677.   *
  21678.   *        Entry
  21679.   *            pbValue  - Value buffer
  21680.   *            cbValue  - Length of value buffer
  21681.   *            pcbValue - USHORT to receive actual value length
  21682.   *
  21683.   *        Exit-Success
  21684.   *            Returns non-zero pointer to value; caller MUST free!
  21685.   *                If value is ASCII
  21686.   *                    *pcbValue == 0;
  21687.   *                If value is BINARY
  21688.   *                    *pcbValue == length of value;
  21689.   *
  21690.   *        Exit-Failure
  21691.   *            Returns NULL
  21692.   *
  21693.   *
  21694.   *  EAT_MVMT - Multi-value, Multi-type
  21695.   *
  21696.   *        +------+----------+-------+------+--------+-------+---+---+---+---+
  21697.   *        | Type | Codepage | Count | Type | Length | Value |...| T | L | V |
  21698.   *        +------+----------+-------+------+--------+-------+---+---+---+---+
  21699.   *           us            us             us      us      us       ?
  21700.   *        \________________________/ \_____________________/     \_________/
  21701.   *           MVMT header                          Value 1                 Val
  21702.   *
  21703.   */
  21704.  char * TranslateValue(char *pbValue,USHORT cbValue,USHORT *pcbValue)
  21705.  {
  21706.      USHORT cb=cbValue;
  21707.      USHORT codePage;
  21708.      USHORT cValue;
  21709.      char * pbDst;
  21710.      char * pbSrc;
  21711.      char * pszNew;
  21712.      USHORT type;
  21713.  
  21714.      // Parse MVMT header, if present
  21715.  
  21716.      pbSrc = pbValue;
  21717.  
  21718.      type = *(USHORT *)pbSrc;                // Get EA value type
  21719.      if (type == EAT_MVMT) {
  21720.          pbSrc += sizeof(USHORT);        // Skip type
  21721.          codePage = *((USHORT*)pbSrc)++; // Get code page
  21722.          cValue = *((USHORT*)pbSrc)++;        // Get count of values
  21723.          if (cValue != 1)                // Not exactly one value
  21724.              return NULL;                //  Fail
  21725.          type = *(USHORT *)pbSrc;        // Get EA value type
  21726.      }
  21727.  
  21728.  
  21729.      // Parse value
  21730.  
  21731.      if ( (type == EAT_ASCII) || (type == EAT_BINARY) ) {
  21732.          pbSrc += sizeof(USHORT);        // Skip type
  21733.          cb = *((USHORT *)pbSrc)++;        // Get data length
  21734.  
  21735.          // Allocate buffer for data
  21736.  
  21737.          pszNew = MemAlloc(cb+1);        // Leave room for NUL, in ASCII case
  21738.          if (pszNew == NULL)
  21739.              return NULL;
  21740.          pbDst = pszNew;
  21741.  
  21742.          // Copy data
  21743.  
  21744.          memcpy(pbDst,pbSrc,cb);         // Copy value
  21745.          pbDst += cb;                        // Advance destination pointer
  21746.  
  21747.          if (type == EAT_ASCII) {
  21748.              *pbDst++ = '\0';                // Terminate ASCIIZ string
  21749.              *pcbValue = 0;                // Indicate value is ASCIIZ
  21750.          }
  21751.          else
  21752.              *pcbValue = cb;                // Indicate value is binary
  21753.          return pszNew;                        // Return value
  21754.      }
  21755.      else
  21756.          return NULL;                        //  Fail
  21757.  }
  21758.  
  21759.  
  21760.  /***        EASetValue - Create/Change/Delete an EA
  21761.   *
  21762.   *        Entry
  21763.   *            pszFile  - file path
  21764.   *            pszName  - EA name
  21765.   *            cbValue  - EA length; 0 => pszValue is ASCIIZ
  21766.   *            pszValue - EA value; NULL to delete EA
  21767.   *
  21768.   *        Exit-Success
  21769.   *            returns TRUE
  21770.   *
  21771.   *        Exit-Failure
  21772.   *            returns FALSE
  21773.   *
  21774.   */
  21775.  BOOL EASetValue(char *pszFile,char *pszName,USHORT cbValue,char *pszValue)
  21776.  {
  21777.      USHORT        cbName;
  21778.      EAOP        eaop;
  21779.      FEA *        pfea;
  21780.      FEALIST *        pFEAList;
  21781.      char *        psz;
  21782.      USHORT        rc;
  21783.      USHORT        type;
  21784.  
  21785.      // Determine operation
  21786.  
  21787.      if (pszValue == NULL) {                // Delete this EA
  21788.          type = EAT_ASCII;
  21789.          cbValue = 0;
  21790.      }
  21791.      else if (cbValue == 0) {                // Create/Change value
  21792.          type = EAT_ASCII;
  21793.          cbValue = strlen(pszValue);        // Compute length (do not count NU
  21794.      }
  21795.      else {                                // Create/Change Binary value
  21796.          type = EAT_BINARY;
  21797.      }
  21798.  
  21799.      //
  21800.      // Alloc FEA List
  21801.      //
  21802.      pFEAList = MemAlloc(CB_FEAL);
  21803.      if (pFEAList == NULL)
  21804.          return FALSE;
  21805.  
  21806.      cbName = strlen(pszName);
  21807.  
  21808.      //
  21809.      // Build EA structure
  21810.      //
  21811.      pfea = (FEA *)pFEAList->list;        // Point at first FEA
  21812.      pfea->fEA = 0;                        // No flag settings
  21813.      pfea->cbName = (UCHAR)cbName;        // Set name length
  21814.      pfea->cbValue = cbValue;                // Set value length
  21815.  
  21816.      psz = (char *)pfea + sizeof(FEA);        // Point at location for name
  21817.      memcpy(psz,pszName,cbName+1);        // Copy Name *and* NUL
  21818.      psz += cbName+1;                        // Point at location for value
  21819.      if (cbValue > 0) {                        // Edit/Create EA
  21820.          *((USHORT *)psz)++ = EAT_MVMT;        // Set MVMT type (to record cod
  21821.          *((USHORT *)psz)++ = NULL;        // Set codepage
  21822.          *((USHORT *)psz)++ = 1;         // Only one TLV record
  21823.          *((USHORT *)psz)++ = type;        // Set EA type
  21824.          *((USHORT *)psz)++ = cbValue;        // Set ASCII length
  21825.  
  21826.          pfea->cbValue += 5*sizeof(USHORT); // MVMT header and type and length
  21827.          memcpy(psz,pszValue,cbValue);        // Copy Value
  21828.      }
  21829.      pfea = (FEA *)(psz + cbValue);        // Point at byte after FEA
  21830.  
  21831.      //
  21832.      // Set size of FEA List (only one FEA)
  21833.      //
  21834.  
  21835.      pFEAList->cbList = (char *)pfea - (char *)pFEAList;
  21836.  
  21837.      eaop.fpGEAList = NULL;
  21838.      eaop.fpFEAList = pFEAList;
  21839.  
  21840.      rc = DosSetPathInfo(pszFile,            // File path
  21841.                          FIL_QUERYEASIZE,    // Set EA
  21842.                          (PBYTE)&eaop,            // EAOP structure
  21843.                          sizeof(eaop),            // Size of EAOP
  21844.                          0,                    // Options
  21845.                          0L);                    // Reserved
  21846.      MemFree(pFEAList);
  21847.      return (rc == 0);
  21848.  }
  21849.  
  21850.  
  21851.  EDPLINE.C
  21852.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\EDPLINE\EDPLINE.C
  21853.  
  21854.  /*
  21855.      edpline.c -- polyline editor, for practice in mouse handling
  21856.      Created by Microsoft Corporation, 1989
  21857.  */
  21858.  #define INCL_DOSMEMMGR
  21859.  #define INCL_WINWINDOWMGR
  21860.  #define INCL_WINMESSAGEMGR
  21861.  #define INCL_WINSWITCHLIST
  21862.  #define INCL_WINDIALOGS
  21863.  #define INCL_GPIBITMAPS
  21864.  #define INCL_GPIPRIMITIVES
  21865.  #define INCL_WINMENUS
  21866.  #define        INCL_WININPUT
  21867.  #define        INCL_WINFRAMEMGR
  21868.  #include <os2.h>
  21869.  
  21870.  #include <stdio.h>
  21871.  #include <stdlib.h>
  21872.  
  21873.  #include "edpline.h"
  21874.  
  21875.  
  21876.  
  21877.  #define        abs(x)                        (((x) > 0) ? (x) : -(x))
  21878.  #define PRIM_POLYLINE                0x0001
  21879.  #define PRIM_POLYFILLET         0x0002
  21880.  #define PRIM_POLYSPLINE         0x0004
  21881.  #define PRIM_POINTARC                0x0008
  21882.  
  21883.  
  21884.  /************************************************************************
  21885.  *
  21886.  *   Function declarations
  21887.  *
  21888.  ************************************************************************/
  21889.  
  21890.  /* Private functions */
  21891.  
  21892.  VOID   cdecl main(VOID);
  21893.  BOOL   InitGlobals(VOID);
  21894.  BOOL   InitApp(VOID);
  21895.  VOID   Close(HWND);
  21896.  VOID   Command(HWND, USHORT);
  21897.  VOID   Paint(HPS, BOOL);
  21898.  VOID   MouseMove(HWND, MPARAM);
  21899.  VOID   ButtonUp(HWND, USHORT);
  21900.  VOID   ButtonDown(HWND, USHORT, MPARAM);
  21901.  USHORT IsPtInList(PPOINTL);
  21902.  USHORT AddPtToList(PPOINTL);
  21903.  BOOL   IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
  21904.  VOID   DrawPrimitive(HPS, USHORT);
  21905.  VOID   DrawPolyLine(HPS);
  21906.  VOID   DrawPolyFillet(HPS);
  21907.  VOID   DrawPolySpline(HPS);
  21908.  VOID   DrawPointArc(HPS);
  21909.  VOID   DrawControlPoints(HPS, LONG, PPOINTL);
  21910.  VOID   MyMessageBox(HWND, PSZ);
  21911.  VOID   SwapLong(PLONG, PLONG);
  21912.  
  21913.  /* Exported functions */
  21914.  
  21915.  ULONG        EXPENTRY WndProc(HWND, USHORT, MPARAM, MPARAM);
  21916.  MRESULT EXPENTRY AboutDlgProc(HWND, USHORT, MPARAM, MPARAM);
  21917.  
  21918.  
  21919.  
  21920.  /************************************************************************
  21921.  *
  21922.  *   Global Variables
  21923.  *
  21924.  ************************************************************************/
  21925.  
  21926.  typedef struct
  21927.  {
  21928.      HAB  hab;
  21929.      HMQ  hMsgQ;
  21930.      HWND hwndFrame;
  21931.      HWND hwnd;
  21932.  
  21933.      ULONG   flPrim;
  21934.      BOOL    fDisplayControlPoints;
  21935.      LONG    cptl;
  21936.      PPOINTL pptl;
  21937.  
  21938.      USHORT  usPtGrabbed;
  21939.      BOOL    fDragging;
  21940.  
  21941.      ULONG   ulHitPrecision;
  21942.  
  21943.  } GLOBALDATA;
  21944.  GLOBALDATA global;
  21945.  
  21946.  
  21947.  
  21948.  
  21949.  /************************************************************************
  21950.  *
  21951.  *   main
  21952.  *
  21953.  *   WinInitialize resizes our ring 2 stack, among other things, so
  21954.  *   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
  21955.  *   us as a REAL PM app. (as well as the WINDOWAPI statement in the .DEF
  21956.  *   file...)   Call a sub to register our window class and create a window.
  21957.  *   Loop over messages.  Exit cleanly.
  21958.  *
  21959.  ************************************************************************/
  21960.  
  21961.  VOID cdecl
  21962.  main()
  21963.  {
  21964.      QMSG qMsg;
  21965.      int iRet = 0;
  21966.  
  21967.  
  21968.      global.hab         = WinInitialize(0);
  21969.      global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
  21970.  
  21971.      if (InitApp())
  21972.          while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
  21973.              WinDispatchMsg( global.hab, (PQMSG)&qMsg );
  21974.      else
  21975.          iRet = -1;
  21976.  
  21977.      WinDestroyWindow( global.hwndFrame );
  21978.      WinDestroyMsgQueue( global.hMsgQ );
  21979.      WinTerminate( global.hab );
  21980.      DosExit(EXIT_PROCESS, iRet);
  21981.  }
  21982.  
  21983.  
  21984.  
  21985.  
  21986.  /****************************************************************************
  21987.  *
  21988.  *   InitGlobals
  21989.  *
  21990.  *   Initialize global variables.
  21991.  *
  21992.  ****************************************************************************/
  21993.  
  21994.  BOOL
  21995.  InitGlobals()
  21996.  {
  21997.      global.flPrim = PRIM_POLYLINE;
  21998.      global.fDisplayControlPoints = TRUE;
  21999.  
  22000.      global.cptl = 0L;
  22001.      global.pptl = NULL;
  22002.      if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  22003.                     ((PUSHORT)&global.pptl)+1, 0))
  22004.          return FALSE;
  22005.  
  22006.      global.usPtGrabbed = -1;
  22007.      global.fDragging = FALSE;
  22008.      global.ulHitPrecision = 0L;
  22009.  
  22010.      return TRUE;
  22011.  }
  22012.  
  22013.  
  22014.  
  22015.  
  22016.  /****************************************************************************
  22017.  *
  22018.  *   InitApp
  22019.  *
  22020.  *   Register application window class and creates standard window.
  22021.  *
  22022.  ****************************************************************************/
  22023.  
  22024.  #define INIT_MENU_ITEM(val, var)     \
  22025.          TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
  22026.  
  22027.  BOOL
  22028.  InitApp()
  22029.  {
  22030.      char szTitle[24];
  22031.      ULONG ctldata;
  22032.      PID pid;
  22033.      TID tid;
  22034.      HSWITCH hsw;
  22035.      static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
  22036.                               SWL_JUMPABLE, "Edit Polyline", 0 };
  22037.  
  22038.      if (!InitGlobals())
  22039.          return FALSE;
  22040.  
  22041.  
  22042.      /*  Register Application Window Class  */
  22043.  
  22044.      WinLoadString( global.hab, (HMODULE) NULL, IDS_TITLE, sizeof(szTitle), (P
  22045.      if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
  22046.              CS_SIZEREDRAW, 0 ))
  22047.          return FALSE;
  22048.  
  22049.  
  22050.  
  22051.      /* Create a window instance of class "PolyLine Editor" */
  22052.  
  22053.      ctldata = FCF_STANDARD &
  22054.       ~(ULONG)(FCF_ICON | FCF_ACCELTABLE | FCF_TASKLIST);
  22055.  
  22056.      if (global.hwndFrame = WinCreateStdWindow(
  22057.          HWND_DESKTOP,                   /* specify desktop as parent window
  22058.          WS_VISIBLE,                   /* window styles
  22059.          &ctldata,                   /* frame creation flags
  22060.          (PCH)szTitle,                   /* window class name
  22061.          (PCH)szTitle,                   /* name appearing in window caption
  22062.          0L,                           /*
  22063.          (HMODULE)NULL,                   /* use current executable module id
  22064.          IDR_EDPLINE,                   /* menu id
  22065.          (HWND FAR *)&global.hwnd   /* window handle
  22066.          ))
  22067.      {
  22068.          INIT_MENU_ITEM(IDM_CTLPOINTS, global.fDisplayControlPoints);
  22069.  
  22070.          if (global.flPrim & PRIM_POLYLINE)
  22071.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYLINE);
  22072.          if (global.flPrim & PRIM_POLYFILLET)
  22073.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYFILLET);
  22074.          if (global.flPrim & PRIM_POLYSPLINE)
  22075.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYSPLINE);
  22076.          if (global.flPrim & PRIM_POINTARC)
  22077.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POINTARC);
  22078.  
  22079.  
  22080.          /* Add ourselves to the switch list. */
  22081.  
  22082.          WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
  22083.          swctl.hwnd        = global.hwndFrame;
  22084.          swctl.idProcess = pid;
  22085.          hsw = WinAddSwitchEntry(&swctl);
  22086.  
  22087.          return TRUE;
  22088.      }
  22089.      return FALSE;
  22090.  }
  22091.  
  22092.  
  22093.  
  22094.  
  22095.  /************************************************************************
  22096.  *
  22097.  *   WndProc
  22098.  *
  22099.  *   Process messages for the window class.
  22100.  *
  22101.  ************************************************************************/
  22102.  
  22103.  ULONG EXPENTRY
  22104.  WndProc( hwnd, usMsg, mp1, mp2 )
  22105.  HWND   hwnd;
  22106.  USHORT usMsg;
  22107.  MPARAM  mp1;
  22108.  MPARAM  mp2;
  22109.  {
  22110.      HPS   hps;
  22111.  
  22112.  
  22113.      switch (usMsg)
  22114.      {
  22115.      case WM_CLOSE:
  22116.          Close(hwnd);
  22117.          break;
  22118.  
  22119.      case WM_COMMAND:
  22120.          Command(hwnd, LOUSHORT(mp1));
  22121.          break;
  22122.  
  22123.      case WM_PAINT:
  22124.          hps = WinBeginPaint(global.hwnd, NULL, NULL);
  22125.          if (global.ulHitPrecision == 0L)
  22126.          {
  22127.              HDC hdc;
  22128.              LONG cx;
  22129.  
  22130.              if (hdc = WinQueryWindowDC(global.hwnd)) {
  22131.                  DevQueryCaps(hdc, CAPS_MARKER_WIDTH,  1L,  &cx);
  22132.                  global.ulHitPrecision = (cx >> 17) + 1L;
  22133.              } else {
  22134.                  global.ulHitPrecision = 6L;
  22135.              }
  22136.          }
  22137.          Paint(hps, TRUE);
  22138.          WinEndPaint(hps);
  22139.          break;
  22140.  
  22141.      case WM_BUTTON1DOWN:
  22142.      case WM_BUTTON2DOWN:
  22143.          ButtonDown(hwnd, usMsg, mp1);
  22144.          break;
  22145.  
  22146.      case WM_BUTTON1UP:
  22147.      case WM_BUTTON2UP:
  22148.          ButtonUp(hwnd, usMsg);
  22149.          break;
  22150.  
  22151.      case WM_MOUSEMOVE:
  22152.          MouseMove(hwnd, mp1);
  22153.          return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  22154.          break;
  22155.  
  22156.      default:
  22157.          return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  22158.          break;
  22159.      }
  22160.  
  22161.      return FALSE;
  22162.  }
  22163.  
  22164.  
  22165.  
  22166.  
  22167.  /************************************************************************
  22168.  *
  22169.  *   MouseMove
  22170.  *
  22171.  ************************************************************************/
  22172.  
  22173.  VOID
  22174.  MouseMove(hwnd, mp1)
  22175.  HWND hwnd;
  22176.  MPARAM mp1;
  22177.  {
  22178.      POINTL ptl;
  22179.      HPS hps;
  22180.  
  22181.      if (hwnd == global.hwnd)
  22182.          if (global.fDragging)
  22183.          {
  22184.              ptl.x = (LONG) LOUSHORT(mp1);
  22185.              ptl.y = (LONG) HIUSHORT(mp1);
  22186.  
  22187.              if (global.usPtGrabbed != -1)
  22188.              {
  22189.                  hps = WinGetPS(hwnd);
  22190.                  Paint(hps, FALSE);
  22191.  
  22192.                  *(global.pptl+global.usPtGrabbed) = ptl;
  22193.  
  22194.                  Paint(hps, FALSE);
  22195.                  WinReleasePS(hps);
  22196.              }
  22197.          }
  22198.  }
  22199.  
  22200.  
  22201.  
  22202.  
  22203.  /************************************************************************
  22204.  *
  22205.  *   ButtonUp
  22206.  *
  22207.  ************************************************************************/
  22208.  
  22209.  VOID
  22210.  ButtonUp(hwnd, usMsg)
  22211.  HWND hwnd;
  22212.  USHORT usMsg;
  22213.  {
  22214.      int i;
  22215.      HPS hps;
  22216.  
  22217.  
  22218.      if (hwnd == global.hwnd)
  22219.          if (global.fDragging)
  22220.          {
  22221.              global.fDragging = FALSE;
  22222.              if (global.usPtGrabbed != -1)
  22223.              {
  22224.                  if (usMsg == WM_BUTTON2UP)
  22225.                  {
  22226.                      hps = WinGetPS(hwnd);
  22227.                      Paint(hps, FALSE);
  22228.  
  22229.                      if ((i = global.usPtGrabbed) < (int) global.cptl-1)
  22230.                          while (i < (int) global.cptl-1)
  22231.                          {
  22232.                              global.pptl[i] = global.pptl[i+1];
  22233.                              ++i;
  22234.                          }
  22235.  
  22236.                      --global.cptl;
  22237.                      global.usPtGrabbed = -1;
  22238.  
  22239.                      Paint(hps, FALSE);
  22240.                      WinReleasePS(hps);
  22241.                  }
  22242.                  else        /* WM_BUTTON1UP */
  22243.                      global.usPtGrabbed = -1;
  22244.              }
  22245.          }
  22246.  }
  22247.  
  22248.  
  22249.  
  22250.  
  22251.  /************************************************************************
  22252.  *
  22253.  *   ButtonDown
  22254.  *
  22255.  ************************************************************************/
  22256.  
  22257.  VOID
  22258.  ButtonDown(hwnd, usMsg, mp1)
  22259.  HWND hwnd;
  22260.  USHORT usMsg;
  22261.  MPARAM mp1;
  22262.  {
  22263.      POINTL ptl;
  22264.      HPS hps;
  22265.      USHORT usNewPtGrabbed;
  22266.  
  22267.  
  22268.      if (hwnd == global.hwnd)
  22269.          if (!global.fDragging)
  22270.          {
  22271.              global.fDragging = TRUE;
  22272.  
  22273.              ptl.x = (LONG) LOUSHORT(mp1);
  22274.              ptl.y = (LONG) HIUSHORT(mp1);
  22275.  
  22276.              if ((usNewPtGrabbed = IsPtInList(&ptl)) != -1)
  22277.                  global.usPtGrabbed = usNewPtGrabbed;
  22278.  
  22279.              if (usMsg == WM_BUTTON1DOWN)
  22280.              {
  22281.                  hps = WinGetPS(hwnd);
  22282.                  Paint(hps, FALSE);
  22283.  
  22284.                  if (usNewPtGrabbed == -1)
  22285.                      global.usPtGrabbed = AddPtToList(&ptl);
  22286.                  else
  22287.                      global.usPtGrabbed = usNewPtGrabbed;
  22288.  
  22289.                  Paint(hps, FALSE);
  22290.                  WinReleasePS(hps);
  22291.  
  22292.                  if (global.usPtGrabbed == -1)
  22293.                      MyMessageBox(global.hwnd, "Cannot add any more points.");
  22294.              }
  22295.          }
  22296.  }
  22297.  
  22298.  
  22299.  
  22300.  
  22301.  /************************************************************************
  22302.  *
  22303.  *   IsPtInList
  22304.  *
  22305.  ************************************************************************/
  22306.  
  22307.  USHORT
  22308.  IsPtInList(pptl)
  22309.  PPOINTL pptl;
  22310.  {
  22311.      int i;
  22312.  
  22313.  
  22314.      /* try to find pptl in the points we already have */
  22315.      for (i = 0; i < (int) global.cptl; ++i)
  22316.          if (((abs(pptl->x - global.pptl[i].x))
  22317.                  <= (LONG) global.ulHitPrecision)
  22318.           && ((abs(pptl->y - global.pptl[i].y))
  22319.                  <= (LONG) global.ulHitPrecision))
  22320.                  return i;
  22321.  
  22322.      /* couldn't find it */
  22323.      return -1;
  22324.  }
  22325.  
  22326.  
  22327.  
  22328.  
  22329.  /************************************************************************
  22330.  *
  22331.  *   AddPtToList
  22332.  *
  22333.  ************************************************************************/
  22334.  
  22335.  USHORT
  22336.  AddPtToList(pptl)
  22337.  PPOINTL pptl;
  22338.  {
  22339.      int i, j;
  22340.  
  22341.      if (global.cptl < CPTLMAX)
  22342.      {
  22343.          /* check for new points lying on a line segment */
  22344.          for (i = 0; i < (int) (global.cptl - 1L); ++i)
  22345.              if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
  22346.              {
  22347.                  for (j = (int) global.cptl; j > i+1; --j)
  22348.                      global.pptl[j] = global.pptl[j - 1];
  22349.                  global.pptl[i+1] = *pptl;
  22350.                  ++global.cptl;
  22351.                  return i+1;
  22352.              }
  22353.  
  22354.          /* append the point */
  22355.  
  22356.          i = (int) global.cptl;
  22357.          global.pptl[i] = *pptl;
  22358.          ++global.cptl;
  22359.          return i;
  22360.      }
  22361.  
  22362.      return -1;
  22363.  }
  22364.  
  22365.  
  22366.  
  22367.  
  22368.  /************************************************************************
  22369.  *
  22370.  *   IsPtCloseToLine
  22371.  *
  22372.  ************************************************************************/
  22373.  
  22374.  BOOL
  22375.  IsPtCloseToLine(pptl1, pptl2, pptlTest)
  22376.  PPOINTL pptl1;
  22377.  PPOINTL pptl2;
  22378.  PPOINTL pptlTest;
  22379.  {
  22380.      POINTL ptlLL, ptlUR;
  22381.      LONG dx, dy, yIntercept, result;
  22382.  
  22383.  
  22384.      /* find the bounding box of the line segment */
  22385.  
  22386.      ptlLL = *pptl1;        /* assume line goes lower left to upper right */
  22387.      ptlUR = *pptl2;
  22388.      if (pptl1->x > pptl2->x)
  22389.          SwapLong(&ptlLL.x, &ptlUR.x);
  22390.      if (pptl1->y > pptl2->y)
  22391.          SwapLong(&ptlLL.y, &ptlUR.y);
  22392.  
  22393.  
  22394.      /* adjust the bounding box if it's too narrow */
  22395.  
  22396.      dx = pptl2->x - pptl1->x;
  22397.      if (abs(dx) <= (LONG) (global.ulHitPrecision >> 1))
  22398.      {
  22399.          ptlLL.x -= (LONG) (global.ulHitPrecision >> 1);
  22400.          ptlUR.x += (LONG) (global.ulHitPrecision >> 1);
  22401.      }
  22402.      dy = pptl2->y - pptl1->y;
  22403.      if (abs(dy) <= (LONG) (global.ulHitPrecision >> 1))
  22404.      {
  22405.          ptlLL.y -= (LONG) (global.ulHitPrecision >> 1);
  22406.          ptlUR.y += (LONG) (global.ulHitPrecision >> 1);
  22407.      }
  22408.  
  22409.  
  22410.      /* see if the test point is in the bounding box of the line segment */
  22411.  
  22412.      if ((pptlTest->x >= ptlLL.x) &&
  22413.          (pptlTest->x <= ptlUR.x) &&
  22414.          (pptlTest->y >= ptlLL.y) &&
  22415.          (pptlTest->y <= ptlUR.y))
  22416.      {
  22417.          /* test for special cases */
  22418.  
  22419.          if (dx == 0)
  22420.          {
  22421.              if (abs(pptlTest->x - pptl1->x) <= (LONG) global.ulHitPrecision)
  22422.                  return TRUE;
  22423.              else
  22424.                  return FALSE;
  22425.          }
  22426.  
  22427.          if (dy == 0)
  22428.          {
  22429.              if (abs(pptlTest->y - pptl1->y) <= (LONG) global.ulHitPrecision)
  22430.                  return TRUE;
  22431.              else
  22432.                  return FALSE;
  22433.          }
  22434.  
  22435.  
  22436.          /* test for general case */
  22437.  
  22438.          yIntercept = pptl1->y - (pptl1->x * dy) / dx;
  22439.  
  22440.          result = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
  22441.          if (abs(result) <= (LONG) global.ulHitPrecision)
  22442.              return TRUE;
  22443.      }
  22444.  
  22445.      return FALSE;
  22446.  }
  22447.  
  22448.  
  22449.  
  22450.  
  22451.  /************************************************************************
  22452.  *
  22453.  *   SwapLong
  22454.  *
  22455.  ************************************************************************/
  22456.  
  22457.  VOID
  22458.  SwapLong(pl1, pl2)
  22459.  PLONG pl1, pl2;
  22460.  {
  22461.      LONG lTmp;
  22462.  
  22463.      lTmp = *pl1;
  22464.      *pl1 = *pl2;
  22465.      *pl2 = lTmp;
  22466.  }
  22467.  
  22468.  
  22469.  
  22470.  
  22471.  /************************************************************************
  22472.  *
  22473.  *   Close
  22474.  *
  22475.  ************************************************************************/
  22476.  
  22477.  VOID
  22478.  Close(hwnd)
  22479.  HWND hwnd;
  22480.  {
  22481.      WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  22482.  }
  22483.  
  22484.  
  22485.  
  22486.  
  22487.  /************************************************************************
  22488.  *
  22489.  *   Command
  22490.  *
  22491.  *   Dispatches menu commands to the proper handlers.
  22492.  *
  22493.  ************************************************************************/
  22494.  
  22495.  #define UPDATE_MENU_BOOL(var, val)                                \
  22496.          {                                                        \
  22497.              TOGGLE_BOOL((var));                                 \
  22498.              TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var));        \
  22499.          }
  22500.  
  22501.  #define UPDATE_MENU_LIST(var, val)                                \
  22502.          {                                                        \
  22503.              UNCHECK_MENU_ITEM(global.hwndFrame, (var));         \
  22504.              (var) = (val);                                        \
  22505.              CHECK_MENU_ITEM(global.hwndFrame, (var));                \
  22506.          }
  22507.  
  22508.  VOID
  22509.  Command(hwnd, id)
  22510.  HWND hwnd;
  22511.  USHORT id;
  22512.  {
  22513.      HPS hps;
  22514.      BOOL fRedraw = FALSE;
  22515.      int rc;
  22516.  
  22517.      switch (id)
  22518.      {
  22519.      case IDM_ABOUT:
  22520.          rc = WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, (HMODULE) NULL, IDD_
  22521.          fRedraw = FALSE;
  22522.          break;
  22523.  
  22524.      case IDM_NOPRIM:
  22525.          global.flPrim = 0L;
  22526.          TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYLINE, 0);
  22527.          TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYFILLET, 0);
  22528.          TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYSPLINE, 0);
  22529.          fRedraw = TRUE;
  22530.          break;
  22531.  
  22532.      case IDM_POLYLINE:
  22533.          global.flPrim ^= PRIM_POLYLINE;
  22534.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYLINE
  22535.          fRedraw = TRUE;
  22536.          break;
  22537.  
  22538.      case IDM_POLYFILLET:
  22539.          global.flPrim ^= PRIM_POLYFILLET;
  22540.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYFILL
  22541.          fRedraw = TRUE;
  22542.          break;
  22543.  
  22544.      case IDM_POLYSPLINE:
  22545.          global.flPrim ^= PRIM_POLYSPLINE;
  22546.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYSPLI
  22547.          fRedraw = TRUE;
  22548.          break;
  22549.  
  22550.      case IDM_POINTARC:
  22551.          global.flPrim ^= PRIM_POINTARC;
  22552.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POINTARC
  22553.          fRedraw = TRUE;
  22554.          break;
  22555.  
  22556.      case IDM_CTLPOINTS:
  22557.          UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
  22558.          fRedraw = TRUE;
  22559.          break;
  22560.  
  22561.      case IDM_CLEARALL:
  22562.          global.cptl = 0L;
  22563.          fRedraw = TRUE;
  22564.          break;
  22565.      }
  22566.  
  22567.      if (fRedraw)
  22568.      {
  22569.          hps = WinGetPS(hwnd);
  22570.          Paint(hps, TRUE);
  22571.          WinReleasePS(hps);
  22572.      }
  22573.  }
  22574.  
  22575.  
  22576.  
  22577.  
  22578.  /************************************************************************
  22579.  *
  22580.  *   Paint
  22581.  *
  22582.  ************************************************************************/
  22583.  
  22584.  VOID
  22585.  Paint(hps, fClearScreen)
  22586.  HPS  hps;
  22587.  BOOL fClearScreen;
  22588.  {
  22589.      LINEBUNDLE lb;
  22590.      RECTL rcl;
  22591.  
  22592.  
  22593.  
  22594.      if (fClearScreen)
  22595.      {
  22596.          /* clear the screen */
  22597.          WinQueryWindowRect(global.hwnd, &rcl);
  22598.          GpiBitBlt(hps, NULL, 2L, (PPOINTL) &rcl, ROP_ONE, 0L);
  22599.      }
  22600.  
  22601.  
  22602.      if (global.cptl > 0L)
  22603.      {
  22604.          if (global.fDisplayControlPoints)
  22605.          {
  22606.              if (fClearScreen)
  22607.                  /* draw all the control points */
  22608.                  DrawControlPoints(hps, global.cptl, global.pptl);
  22609.              else if (global.usPtGrabbed != -1)
  22610.                  /* draw just the control point that moved */
  22611.                  DrawControlPoints(hps, 1L, global.pptl+global.usPtGrabbed);
  22612.          }
  22613.  
  22614.          /* set mix mode to xor */
  22615.          lb.usMixMode = FM_XOR;
  22616.          GpiSetAttrs(hps, PRIM_LINE, LBB_MIX_MODE, 0L, &lb);
  22617.  
  22618.          /* draw the current primitives */
  22619.  
  22620.          if (global.flPrim & PRIM_POLYLINE)
  22621.          {
  22622.              lb.lColor = CLR_BROWN;
  22623.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  22624.              DrawPrimitive(hps, IDM_POLYLINE);
  22625.          }
  22626.  
  22627.          if (global.flPrim & PRIM_POLYFILLET)
  22628.          {
  22629.              lb.lColor = CLR_DARKCYAN;
  22630.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  22631.              DrawPrimitive(hps, IDM_POLYFILLET);
  22632.          }
  22633.  
  22634.          if (global.flPrim & PRIM_POLYSPLINE)
  22635.          {
  22636.              lb.lColor = CLR_DARKPINK;
  22637.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  22638.              DrawPrimitive(hps, IDM_POLYSPLINE);
  22639.          }
  22640.  
  22641.          if (global.flPrim & PRIM_POINTARC)
  22642.          {
  22643.              lb.lColor = CLR_BACKGROUND;
  22644.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  22645.              DrawPrimitive(hps, IDM_POINTARC);
  22646.          }
  22647.      }
  22648.  }
  22649.  
  22650.  
  22651.  
  22652.  
  22653.  /************************************************************************
  22654.  *
  22655.  *   DrawPrimitive
  22656.  *
  22657.  ************************************************************************/
  22658.  
  22659.  VOID
  22660.  DrawPrimitive(hps, usPrim)
  22661.  HPS hps;
  22662.  USHORT usPrim;
  22663.  {
  22664.      switch ( usPrim )
  22665.      {
  22666.      case IDM_POLYLINE:
  22667.          DrawPolyLine(hps);
  22668.          break;
  22669.  
  22670.      case IDM_POLYFILLET:
  22671.          DrawPolyFillet(hps);
  22672.          break;
  22673.  
  22674.      case IDM_POLYSPLINE:
  22675.          DrawPolySpline(hps);
  22676.          break;
  22677.  
  22678.      case IDM_POINTARC:
  22679.          DrawPointArc(hps);
  22680.          break;
  22681.      }
  22682.  }
  22683.  
  22684.  
  22685.  
  22686.  
  22687.  /************************************************************************
  22688.  *
  22689.  *   DrawPolyLine
  22690.  *
  22691.  ************************************************************************/
  22692.  
  22693.  VOID
  22694.  DrawPolyLine(hps)
  22695.  HPS hps;
  22696.  {
  22697.      GpiSetCurrentPosition( hps, global.pptl );
  22698.      GpiPolyLine( hps, global.cptl-1L, global.pptl+1 );
  22699.  }
  22700.  
  22701.  
  22702.  
  22703.  
  22704.  /************************************************************************
  22705.  *
  22706.  *   DrawPolyFillet
  22707.  *
  22708.  ************************************************************************/
  22709.  
  22710.  VOID
  22711.  DrawPolyFillet(hps)
  22712.  HPS hps;
  22713.  {
  22714.      if (global.cptl > 2)
  22715.      {
  22716.          GpiSetCurrentPosition( hps, global.pptl );
  22717.          GpiPolyFillet( hps, global.cptl-1L, global.pptl+1 );
  22718.      }
  22719.  }
  22720.  
  22721.  
  22722.  
  22723.  
  22724.  /************************************************************************
  22725.  *
  22726.  *   DrawPolySpline
  22727.  *
  22728.  ************************************************************************/
  22729.  
  22730.  VOID
  22731.  DrawPolySpline(hps)
  22732.  HPS hps;
  22733.  {
  22734.      USHORT cptSlack;        /* # points in pptl not usable by PolySpline */
  22735.  
  22736.      /* GpiPolySpline expects the number of points to be a
  22737.         multiple of 3.  If we have a non-multiple of three,
  22738.         (excluding the first point, which we've used to set
  22739.         the current position), only pass the largest multiple
  22740.         of three, saving the rest for the next go-round. */
  22741.  
  22742.      cptSlack = (int)((global.cptl-1L) % 3) + 1;
  22743.      GpiSetCurrentPosition( hps, global.pptl );
  22744.      GpiPolySpline( hps, global.cptl-cptSlack,
  22745.                     global.pptl+1 );
  22746.  }
  22747.  
  22748.  
  22749.  
  22750.  
  22751.  /************************************************************************
  22752.  *
  22753.  *   DrawPointArc
  22754.  *
  22755.  ************************************************************************/
  22756.  
  22757.  VOID
  22758.  DrawPointArc(hps)
  22759.  HPS hps;
  22760.  {
  22761.      if (global.cptl >= 3L)
  22762.      {
  22763.          GpiSetCurrentPosition( hps, global.pptl );
  22764.          GpiPointArc( hps, global.pptl+1 );
  22765.      }
  22766.  }
  22767.  
  22768.  
  22769.  
  22770.  
  22771.  /************************************************************************
  22772.  *
  22773.  *   DrawControlPoints
  22774.  *
  22775.  ************************************************************************/
  22776.  
  22777.  VOID
  22778.  DrawControlPoints(hps, cptl, pptl)
  22779.  HPS hps;
  22780.  LONG cptl;
  22781.  PPOINTL pptl;
  22782.  {
  22783.      MARKERBUNDLE mb;
  22784.  
  22785.      mb.lColor = CLR_TRUE;
  22786.      mb.usMixMode = FM_XOR;
  22787.      GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR | MBB_MIX_MODE, 0L, &mb);
  22788.  
  22789.      GpiPolyMarker(hps, cptl, pptl);
  22790.  }
  22791.  
  22792.  
  22793.  
  22794.  
  22795.  /************************************************************************
  22796.  *
  22797.  *   MyMessageBox
  22798.  *
  22799.  *   Displays a message box with the given string.  To simplify matters,
  22800.  *   the box will always have the same title ("PolyLine Editor"), will always
  22801.  *   have a single button ("Ok"), will always have an exclamation point
  22802.  *   icon, and will always be application modal.
  22803.  *
  22804.  ************************************************************************/
  22805.  
  22806.  VOID
  22807.  MyMessageBox(hWnd, sz)
  22808.  HWND hWnd;
  22809.  PSZ sz;
  22810.  {
  22811.      static char *szTitle = "PolyLine Editor";
  22812.  
  22813.      WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, (HMODULE) NULL,
  22814.                    MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
  22815.  }
  22816.  
  22817.  MRESULT EXPENTRY AboutDlgProc(hDlg, msg, mp1, mp2)
  22818.  /*
  22819.      About... dialog procedure
  22820.  */
  22821.  HWND        hDlg;
  22822.  USHORT        msg;
  22823.  MPARAM        mp1;
  22824.  MPARAM        mp2;
  22825.  {
  22826.      switch(msg) {
  22827.          case WM_COMMAND:
  22828.              switch(COMMANDMSG(&msg)->cmd) {
  22829.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  22830.                  default: break;
  22831.              }
  22832.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  22833.      }
  22834.      return FALSE;
  22835.  }
  22836.  
  22837.  
  22838.  EDPLINE.C
  22839.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\CLIPVIEW\EDPLINE\EDPLINE.C
  22840.  
  22841.  /*
  22842.      edpline.c -- polyline editor, for practice in mouse handling
  22843.      Created by Microsoft Corporation, 1989
  22844.  */
  22845.  #define INCL_DOSMEMMGR
  22846.  #define INCL_WINWINDOWMGR
  22847.  #define INCL_WINMESSAGEMGR
  22848.  #define INCL_WINSWITCHLIST
  22849.  #define INCL_WINDIALOGS
  22850.  #define INCL_GPIBITMAPS
  22851.  #define INCL_GPIPRIMITIVES
  22852.  #define        INCL_GPITRANSFORMS
  22853.  #define INCL_WINMENUS
  22854.  #define        INCL_WININPUT
  22855.  #define        INCL_WINFRAMEMGR
  22856.  #define        INCL_WINCLIPBOARD
  22857.  #include <os2.h>
  22858.  
  22859.  #include <stdio.h>
  22860.  #include <stdlib.h>
  22861.  
  22862.  #include "edpline.h"
  22863.  
  22864.  
  22865.  
  22866.  #define        abs(x)                        (((x) > 0) ? (x) : -(x))
  22867.  #define PRIM_POLYLINE                0x0001
  22868.  #define PRIM_POLYFILLET         0x0002
  22869.  #define PRIM_POLYSPLINE         0x0004
  22870.  #define PRIM_POINTARC                0x0008
  22871.  
  22872.  
  22873.  /************************************************************************
  22874.  *
  22875.  *   Function declarations
  22876.  *
  22877.  ************************************************************************/
  22878.  
  22879.  /* Private functions */
  22880.  
  22881.  VOID   cdecl main(VOID);
  22882.  BOOL   InitGlobals(VOID);
  22883.  BOOL   InitApp(VOID);
  22884.  VOID   Close(HWND);
  22885.  VOID   Command(HWND, USHORT);
  22886.  VOID   Paint(HPS, BOOL);
  22887.  VOID   MouseMove(HWND, MPARAM);
  22888.  VOID   ButtonUp(HWND, USHORT);
  22889.  VOID   ButtonDown(HWND, USHORT, MPARAM);
  22890.  USHORT IsPtInList(PPOINTL);
  22891.  USHORT AddPtToList(PPOINTL);
  22892.  BOOL   IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
  22893.  VOID   DrawPrimitive(HPS, USHORT);
  22894.  VOID   DrawPolyLine(HPS);
  22895.  VOID   DrawPolyFillet(HPS);
  22896.  VOID   DrawPolySpline(HPS);
  22897.  VOID   DrawPointArc(HPS);
  22898.  VOID   DrawControlPoints(HPS, LONG, PPOINTL);
  22899.  VOID   MyMessageBox(HWND, PSZ);
  22900.  VOID   SwapLong(PLONG, PLONG);
  22901.  
  22902.  /* Exported functions */
  22903.  
  22904.  ULONG        CALLBACK WndProc(HWND, USHORT, MPARAM, MPARAM);
  22905.  MRESULT CALLBACK AboutDlgProc(HWND, USHORT, MPARAM, MPARAM);
  22906.  
  22907.  
  22908.  
  22909.  /************************************************************************
  22910.  *
  22911.  *   Global Variables
  22912.  *
  22913.  ************************************************************************/
  22914.  
  22915.  typedef struct
  22916.  {
  22917.      HAB  hab;
  22918.      HMQ  hMsgQ;
  22919.      HWND hwndFrame;
  22920.      HWND hwnd;
  22921.  
  22922.      ULONG   flPrim;
  22923.      BOOL    fDisplayControlPoints;
  22924.      LONG    cptl;
  22925.      PPOINTL pptl;
  22926.  
  22927.      USHORT  usPtGrabbed;
  22928.      BOOL    fDragging;
  22929.  
  22930.      ULONG   ulHitPrecision;
  22931.  
  22932.      HPS     hpsMetafile;
  22933.      HDC     hdcMetafile;
  22934.      ULONG   hItem;
  22935.      SIZEL   sizlPage;
  22936.      DEVOPENSTRUC dop;
  22937.  
  22938.  } GLOBALDATA;
  22939.  GLOBALDATA global;
  22940.  
  22941.  
  22942.  /************************************************************************
  22943.  *
  22944.  *   main
  22945.  *
  22946.  *   WinInitialize resizes our ring 2 stack, among other things, so
  22947.  *   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
  22948.  *   us as a REAL PM app. (as well as the WINDOWAPI statement in the .DEF
  22949.  *   file...)   Call a sub to register our window class and create a window.
  22950.  *   Loop over messages.  Exit cleanly.
  22951.  *
  22952.  ************************************************************************/
  22953.  
  22954.  VOID cdecl
  22955.  main()
  22956.  {
  22957.      QMSG qMsg;
  22958.      int iRet = 0;
  22959.  
  22960.  
  22961.      global.hab         = WinInitialize(0);
  22962.      global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
  22963.  
  22964.      if (InitApp())
  22965.          while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
  22966.              WinDispatchMsg( global.hab, (PQMSG)&qMsg );
  22967.      else
  22968.          iRet = -1;
  22969.  
  22970.      WinDestroyWindow( global.hwndFrame );
  22971.      WinDestroyMsgQueue( global.hMsgQ );
  22972.      WinTerminate( global.hab );
  22973.      DosExit(EXIT_PROCESS, iRet);
  22974.  }
  22975.  
  22976.  
  22977.  
  22978.  
  22979.  /****************************************************************************
  22980.  *
  22981.  *   InitGlobals
  22982.  *
  22983.  *   Initialize global variables.
  22984.  *
  22985.  ****************************************************************************/
  22986.  
  22987.  BOOL
  22988.  InitGlobals()
  22989.  {
  22990.      global.flPrim = PRIM_POLYLINE;
  22991.      global.fDisplayControlPoints = TRUE;
  22992.  
  22993.      global.cptl = 0L;
  22994.      global.pptl = NULL;
  22995.      if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  22996.                     ((PUSHORT)&global.pptl)+1, 0))
  22997.          return FALSE;
  22998.  
  22999.      global.usPtGrabbed = -1;
  23000.      global.fDragging = FALSE;
  23001.      global.ulHitPrecision = 0L;
  23002.  
  23003.      return TRUE;
  23004.  }
  23005.  
  23006.  
  23007.  
  23008.  
  23009.  /****************************************************************************
  23010.  *
  23011.  *   InitApp
  23012.  *
  23013.  *   Register application window class and creates standard window.
  23014.  *
  23015.  ****************************************************************************/
  23016.  
  23017.  #define INIT_MENU_ITEM(val, var)     \
  23018.          TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
  23019.  
  23020.  BOOL
  23021.  InitApp()
  23022.  {
  23023.      char szTitle[24];
  23024.      ULONG ctldata;
  23025.      PID pid;
  23026.      TID tid;
  23027.      HSWITCH hsw;
  23028.      static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
  23029.                               SWL_JUMPABLE, "Edit Polyline", 0 };
  23030.  
  23031.      if (!InitGlobals())
  23032.          return FALSE;
  23033.  
  23034.  
  23035.      /*  Register Application Window Class  */
  23036.  
  23037.      WinLoadString( global.hab, (HMODULE) NULL, IDS_TITLE, sizeof(szTitle), (P
  23038.      if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
  23039.              CS_SIZEREDRAW, 0 ))
  23040.          return FALSE;
  23041.  
  23042.  
  23043.  
  23044.      /* Create a window instance of class "PolyLine Editor" */
  23045.  
  23046.      ctldata = FCF_STANDARD &
  23047.       ~(ULONG)(FCF_ICON | FCF_TASKLIST);
  23048.  
  23049.      if (global.hwndFrame = WinCreateStdWindow(
  23050.          HWND_DESKTOP,                   /* specify desktop as parent window
  23051.          WS_VISIBLE,                   /* window styles
  23052.          &ctldata,                   /* frame creation flags
  23053.          (PCH)szTitle,                   /* window class name
  23054.          (PCH)szTitle,                   /* name appearing in window caption
  23055.          0L,                           /*
  23056.          (HMODULE)NULL,                   /* use current executable module id
  23057.          IDR_EDPLINE,                   /* menu id
  23058.          (HWND FAR *)&global.hwnd   /* window handle
  23059.          ))
  23060.      {
  23061.          INIT_MENU_ITEM(IDM_CTLPOINTS, global.fDisplayControlPoints);
  23062.  
  23063.          if (global.flPrim & PRIM_POLYLINE)
  23064.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYLINE);
  23065.          if (global.flPrim & PRIM_POLYFILLET)
  23066.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYFILLET);
  23067.          if (global.flPrim & PRIM_POLYSPLINE)
  23068.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYSPLINE);
  23069.          if (global.flPrim & PRIM_POINTARC)
  23070.              CHECK_MENU_ITEM(global.hwndFrame, IDM_POINTARC);
  23071.  
  23072.  
  23073.          /* Add ourselves to the switch list. */
  23074.  
  23075.          WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
  23076.          swctl.hwnd        = global.hwndFrame;
  23077.          swctl.idProcess = pid;
  23078.          hsw = WinAddSwitchEntry(&swctl);
  23079.  
  23080.          return TRUE;
  23081.      }
  23082.      return FALSE;
  23083.  }
  23084.  
  23085.  
  23086.  
  23087.  
  23088.  /************************************************************************
  23089.  *
  23090.  *   WndProc
  23091.  *
  23092.  *   Process messages for the window class.
  23093.  *
  23094.  ************************************************************************/
  23095.  
  23096.  ULONG CALLBACK
  23097.  WndProc( hwnd, usMsg, mp1, mp2 )
  23098.  HWND   hwnd;
  23099.  USHORT usMsg;
  23100.  MPARAM  mp1;
  23101.  MPARAM  mp2;
  23102.  {
  23103.      HPS   hps;
  23104.  
  23105.      switch (usMsg)
  23106.      {
  23107.      case WM_CLOSE:
  23108.          Close(hwnd);
  23109.          break;
  23110.  
  23111.      case WM_COMMAND:
  23112.          Command(hwnd, LOUSHORT(mp1));
  23113.          break;
  23114.  
  23115.      case WM_PAINT:
  23116.          hps = WinBeginPaint(global.hwnd, NULL, NULL);
  23117.  
  23118.          if (global.ulHitPrecision == 0L)
  23119.          {
  23120.              HDC hdc;
  23121.              LONG cx;
  23122.  
  23123.              if (hdc = WinQueryWindowDC(global.hwnd)) {
  23124.                  DevQueryCaps(hdc, CAPS_MARKER_WIDTH,  1L,  &cx);
  23125.                  global.ulHitPrecision = (cx >> 17) + 1L;
  23126.              } else {
  23127.                  global.ulHitPrecision = 6L;
  23128.              }
  23129.          }
  23130.          Paint(hps, TRUE);
  23131.          WinEndPaint(hps);
  23132.          break;
  23133.  
  23134.      case WM_BUTTON1DOWN:
  23135.      case WM_BUTTON2DOWN:
  23136.          ButtonDown(hwnd, usMsg, mp1);
  23137.          break;
  23138.  
  23139.      case WM_BUTTON1UP:
  23140.      case WM_BUTTON2UP:
  23141.          ButtonUp(hwnd, usMsg);
  23142.          break;
  23143.  
  23144.      case WM_MOUSEMOVE:
  23145.          MouseMove(hwnd, mp1);
  23146.          return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  23147.          break;
  23148.  
  23149.      default:
  23150.          return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  23151.          break;
  23152.      }
  23153.  
  23154.      return FALSE;
  23155.  }
  23156.  
  23157.  
  23158.  
  23159.  
  23160.  /************************************************************************
  23161.  *
  23162.  *   MouseMove
  23163.  *
  23164.  ************************************************************************/
  23165.  
  23166.  VOID
  23167.  MouseMove(hwnd, mp1)
  23168.  HWND hwnd;
  23169.  MPARAM mp1;
  23170.  {
  23171.      POINTL ptl;
  23172.      HPS hps;
  23173.  
  23174.      if (hwnd == global.hwnd)
  23175.          if (global.fDragging)
  23176.          {
  23177.              ptl.x = (LONG) LOUSHORT(mp1);
  23178.              ptl.y = (LONG) HIUSHORT(mp1);
  23179.  
  23180.              if (global.usPtGrabbed != -1)
  23181.              {
  23182.                  hps = WinGetPS(hwnd);
  23183.                  Paint(hps, FALSE);
  23184.  
  23185.                  *(global.pptl+global.usPtGrabbed) = ptl;
  23186.  
  23187.                  Paint(hps, FALSE);
  23188.                  WinReleasePS(hps);
  23189.              }
  23190.          }
  23191.  }
  23192.  
  23193.  
  23194.  
  23195.  
  23196.  /************************************************************************
  23197.  *
  23198.  *   ButtonUp
  23199.  *
  23200.  ************************************************************************/
  23201.  
  23202.  VOID
  23203.  ButtonUp(hwnd, usMsg)
  23204.  HWND hwnd;
  23205.  USHORT usMsg;
  23206.  {
  23207.      int i;
  23208.      HPS hps;
  23209.  
  23210.  
  23211.      if (hwnd == global.hwnd)
  23212.          if (global.fDragging)
  23213.          {
  23214.              global.fDragging = FALSE;
  23215.              if (global.usPtGrabbed != -1)
  23216.              {
  23217.                  if (usMsg == WM_BUTTON2UP)
  23218.                  {
  23219.                      hps = WinGetPS(hwnd);
  23220.                      Paint(hps, FALSE);
  23221.  
  23222.                      if ((i = global.usPtGrabbed) < (int) global.cptl-1)
  23223.                          while (i < (int) global.cptl-1)
  23224.                          {
  23225.                              global.pptl[i] = global.pptl[i+1];
  23226.                              ++i;
  23227.                          }
  23228.  
  23229.                      --global.cptl;
  23230.                      global.usPtGrabbed = -1;
  23231.  
  23232.                      Paint(hps, FALSE);
  23233.                      WinReleasePS(hps);
  23234.                  }
  23235.                  else        /* WM_BUTTON1UP */
  23236.                      global.usPtGrabbed = -1;
  23237.              }
  23238.          }
  23239.  }
  23240.  
  23241.  
  23242.  
  23243.  
  23244.  /************************************************************************
  23245.  *
  23246.  *   ButtonDown
  23247.  *
  23248.  ************************************************************************/
  23249.  
  23250.  VOID
  23251.  ButtonDown(hwnd, usMsg, mp1)
  23252.  HWND hwnd;
  23253.  USHORT usMsg;
  23254.  MPARAM mp1;
  23255.  {
  23256.      POINTL ptl;
  23257.      HPS hps;
  23258.      USHORT usNewPtGrabbed;
  23259.  
  23260.  
  23261.      if (hwnd == global.hwnd)
  23262.          if (!global.fDragging)
  23263.          {
  23264.              global.fDragging = TRUE;
  23265.  
  23266.              ptl.x = (LONG) LOUSHORT(mp1);
  23267.              ptl.y = (LONG) HIUSHORT(mp1);
  23268.  
  23269.              if ((usNewPtGrabbed = IsPtInList(&ptl)) != -1)
  23270.                  global.usPtGrabbed = usNewPtGrabbed;
  23271.  
  23272.              if (usMsg == WM_BUTTON1DOWN)
  23273.              {
  23274.                  hps = WinGetPS(hwnd);
  23275.                  Paint(hps, FALSE);
  23276.  
  23277.                  if (usNewPtGrabbed == -1)
  23278.                      global.usPtGrabbed = AddPtToList(&ptl);
  23279.                  else
  23280.                      global.usPtGrabbed = usNewPtGrabbed;
  23281.  
  23282.                  Paint(hps, FALSE);
  23283.                  WinReleasePS(hps);
  23284.  
  23285.                  if (global.usPtGrabbed == -1)
  23286.                      MyMessageBox(global.hwnd, "Cannot add any more points.");
  23287.              }
  23288.          }
  23289.  }
  23290.  
  23291.  
  23292.  
  23293.  
  23294.  /************************************************************************
  23295.  *
  23296.  *   IsPtInList
  23297.  *
  23298.  ************************************************************************/
  23299.  
  23300.  USHORT
  23301.  IsPtInList(pptl)
  23302.  PPOINTL pptl;
  23303.  {
  23304.      int i;
  23305.  
  23306.  
  23307.      /* try to find pptl in the points we already have */
  23308.      for (i = 0; i < (int) global.cptl; ++i)
  23309.          if (((abs(pptl->x - global.pptl[i].x))
  23310.                  <= (LONG) global.ulHitPrecision)
  23311.           && ((abs(pptl->y - global.pptl[i].y))
  23312.                  <= (LONG) global.ulHitPrecision))
  23313.                  return i;
  23314.  
  23315.      /* couldn't find it */
  23316.      return -1;
  23317.  }
  23318.  
  23319.  
  23320.  
  23321.  
  23322.  /************************************************************************
  23323.  *
  23324.  *   AddPtToList
  23325.  *
  23326.  ************************************************************************/
  23327.  
  23328.  USHORT
  23329.  AddPtToList(pptl)
  23330.  PPOINTL pptl;
  23331.  {
  23332.      int i, j;
  23333.  
  23334.      if (global.cptl < CPTLMAX)
  23335.      {
  23336.          /* check for new points lying on a line segment */
  23337.          for (i = 0; i < (int) (global.cptl - 1L); ++i)
  23338.              if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
  23339.              {
  23340.                  for (j = (int) global.cptl; j > i+1; --j)
  23341.                      global.pptl[j] = global.pptl[j - 1];
  23342.                  global.pptl[i+1] = *pptl;
  23343.                  ++global.cptl;
  23344.                  return i+1;
  23345.              }
  23346.  
  23347.          /* append the point */
  23348.  
  23349.          i = (int) global.cptl;
  23350.          global.pptl[i] = *pptl;
  23351.          ++global.cptl;
  23352.          return i;
  23353.      }
  23354.  
  23355.      return -1;
  23356.  }
  23357.  
  23358.  
  23359.  
  23360.  
  23361.  /************************************************************************
  23362.  *
  23363.  *   IsPtCloseToLine
  23364.  *
  23365.  ************************************************************************/
  23366.  
  23367.  BOOL
  23368.  IsPtCloseToLine(pptl1, pptl2, pptlTest)
  23369.  PPOINTL pptl1;
  23370.  PPOINTL pptl2;
  23371.  PPOINTL pptlTest;
  23372.  {
  23373.      POINTL ptlLL, ptlUR;
  23374.      LONG dx, dy, yIntercept, result;
  23375.  
  23376.  
  23377.      /* find the bounding box of the line segment */
  23378.  
  23379.      ptlLL = *pptl1;        /* assume line goes lower left to upper right */
  23380.      ptlUR = *pptl2;
  23381.      if (pptl1->x > pptl2->x)
  23382.          SwapLong(&ptlLL.x, &ptlUR.x);
  23383.      if (pptl1->y > pptl2->y)
  23384.          SwapLong(&ptlLL.y, &ptlUR.y);
  23385.  
  23386.  
  23387.      /* adjust the bounding box if it's too narrow */
  23388.  
  23389.      dx = pptl2->x - pptl1->x;
  23390.      if (abs(dx) <= (LONG) (global.ulHitPrecision >> 1))
  23391.      {
  23392.          ptlLL.x -= (LONG) (global.ulHitPrecision >> 1);
  23393.          ptlUR.x += (LONG) (global.ulHitPrecision >> 1);
  23394.      }
  23395.      dy = pptl2->y - pptl1->y;
  23396.      if (abs(dy) <= (LONG) (global.ulHitPrecision >> 1))
  23397.      {
  23398.          ptlLL.y -= (LONG) (global.ulHitPrecision >> 1);
  23399.          ptlUR.y += (LONG) (global.ulHitPrecision >> 1);
  23400.      }
  23401.  
  23402.  
  23403.      /* see if the test point is in the bounding box of the line segment */
  23404.  
  23405.      if ((pptlTest->x >= ptlLL.x) &&
  23406.          (pptlTest->x <= ptlUR.x) &&
  23407.          (pptlTest->y >= ptlLL.y) &&
  23408.          (pptlTest->y <= ptlUR.y))
  23409.      {
  23410.          /* test for special cases */
  23411.  
  23412.          if (dx == 0)
  23413.          {
  23414.              if (abs(pptlTest->x - pptl1->x) <= (LONG) global.ulHitPrecision)
  23415.                  return TRUE;
  23416.              else
  23417.                  return FALSE;
  23418.          }
  23419.  
  23420.          if (dy == 0)
  23421.          {
  23422.              if (abs(pptlTest->y - pptl1->y) <= (LONG) global.ulHitPrecision)
  23423.                  return TRUE;
  23424.              else
  23425.                  return FALSE;
  23426.          }
  23427.  
  23428.  
  23429.          /* test for general case */
  23430.  
  23431.          yIntercept = pptl1->y - (pptl1->x * dy) / dx;
  23432.  
  23433.          result = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
  23434.          if (abs(result) <= (LONG) global.ulHitPrecision)
  23435.              return TRUE;
  23436.      }
  23437.  
  23438.      return FALSE;
  23439.  }
  23440.  
  23441.  
  23442.  
  23443.  
  23444.  /************************************************************************
  23445.  *
  23446.  *   SwapLong
  23447.  *
  23448.  ************************************************************************/
  23449.  
  23450.  VOID
  23451.  SwapLong(pl1, pl2)
  23452.  PLONG pl1, pl2;
  23453.  {
  23454.      LONG lTmp;
  23455.  
  23456.      lTmp = *pl1;
  23457.      *pl1 = *pl2;
  23458.      *pl2 = lTmp;
  23459.  }
  23460.  
  23461.  
  23462.  
  23463.  
  23464.  /************************************************************************
  23465.  *
  23466.  *   Close
  23467.  *
  23468.  ************************************************************************/
  23469.  
  23470.  VOID
  23471.  Close(hwnd)
  23472.  HWND hwnd;
  23473.  {
  23474.      WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  23475.  }
  23476.  
  23477.  
  23478.  
  23479.  
  23480.  /************************************************************************
  23481.  *
  23482.  *   Command
  23483.  *
  23484.  *   Dispatches menu commands to the proper handlers.
  23485.  *
  23486.  ************************************************************************/
  23487.  
  23488.  #define UPDATE_MENU_BOOL(var, val)                                \
  23489.          {                                                        \
  23490.              TOGGLE_BOOL((var));                                 \
  23491.              TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var));        \
  23492.          }
  23493.  
  23494.  #define UPDATE_MENU_LIST(var, val)                                \
  23495.          {                                                        \
  23496.              UNCHECK_MENU_ITEM(global.hwndFrame, (var));         \
  23497.              (var) = (val);                                        \
  23498.              CHECK_MENU_ITEM(global.hwndFrame, (var));                \
  23499.          }
  23500.  
  23501.  VOID
  23502.  Command(hwnd, id)
  23503.  HWND hwnd;
  23504.  USHORT id;
  23505.  {
  23506.      HPS hps;
  23507.      BOOL fRedraw = FALSE;
  23508.      int rc;
  23509.  
  23510.      switch (id)
  23511.      {
  23512.      case IDM_ABOUT:
  23513.          rc = WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, (HMODULE) NULL, IDD_
  23514.          fRedraw = FALSE;
  23515.          break;
  23516.  
  23517.      case IDM_NOPRIM:
  23518.          global.flPrim = 0L;
  23519.          TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYLINE, 0);
  23520.          TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYFILLET, 0);
  23521.          TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYSPLINE, 0);
  23522.          fRedraw = TRUE;
  23523.          break;
  23524.  
  23525.      case IDM_POLYLINE:
  23526.          global.flPrim ^= PRIM_POLYLINE;
  23527.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYLINE
  23528.          fRedraw = TRUE;
  23529.          break;
  23530.  
  23531.      case IDM_POLYFILLET:
  23532.          global.flPrim ^= PRIM_POLYFILLET;
  23533.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYFILL
  23534.          fRedraw = TRUE;
  23535.          break;
  23536.  
  23537.      case IDM_POLYSPLINE:
  23538.          global.flPrim ^= PRIM_POLYSPLINE;
  23539.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYSPLI
  23540.          fRedraw = TRUE;
  23541.          break;
  23542.  
  23543.      case IDM_POINTARC:
  23544.          global.flPrim ^= PRIM_POINTARC;
  23545.          TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POINTARC
  23546.          fRedraw = TRUE;
  23547.          break;
  23548.  
  23549.      case IDM_CTLPOINTS:
  23550.          UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
  23551.          fRedraw = TRUE;
  23552.          break;
  23553.  
  23554.      case IDM_CLEARALL:
  23555.          global.cptl = 0L;
  23556.          fRedraw = TRUE;
  23557.          break;
  23558.  
  23559.      case IDM_COPY:
  23560.          /*
  23561.              To put this image on the clipboard, create a Metafile DC.
  23562.  
  23563.              Associate a presentation space with the DC, then play the
  23564.              drawing orders into the metafile.
  23565.          */
  23566.          global.dop.pszLogAddress = NULL;
  23567.          global.dop.pszDriverName = "DISPLAY";
  23568.          global.dop.pdriv = NULL;
  23569.          global.dop.pszDataType = NULL;
  23570.  
  23571.          global.hdcMetafile = DevOpenDC(global.hab, OD_METAFILE,
  23572.                              "*", 4L, (PDEVOPENDATA) &global.dop, NULL);
  23573.          global.hpsMetafile = GpiCreatePS(global.hab, global.hdcMetafile,
  23574.                                      &global.sizlPage, PU_PELS | GPIA_ASSOC);
  23575.  
  23576.          Paint(global.hpsMetafile, TRUE);
  23577.          /*
  23578.              Clean up.  A handle to the metafile is obtained when
  23579.              calling DevCloseDC().
  23580.          */
  23581.          GpiAssociate(global.hpsMetafile, NULL);
  23582.          GpiDestroyPS(global.hpsMetafile);
  23583.          global.hItem = (ULONG) DevCloseDC(global.hdcMetafile);
  23584.          /*
  23585.              Be sure to empty the clipboard of other data.  This will
  23586.              also empty previous data stored in other formats.
  23587.              Then, set the clipboard data with type METAFILE, passing
  23588.              the handle to our metafile.
  23589.          */
  23590.          if (WinOpenClipbrd(global.hab)) {
  23591.              WinEmptyClipbrd(global.hab);
  23592.              WinSetClipbrdData(global.hab,global.hItem, CF_METAFILE, CFI_HANDL
  23593.              WinCloseClipbrd(global.hab);
  23594.          }
  23595.          break;
  23596.      }
  23597.  
  23598.      if (fRedraw)
  23599.      {
  23600.          hps = WinGetPS(hwnd);
  23601.          Paint(hps, TRUE);
  23602.          WinReleasePS(hps);
  23603.      }
  23604.  }
  23605.  
  23606.  
  23607.  
  23608.  
  23609.  /************************************************************************
  23610.  *
  23611.  *   Paint
  23612.  *
  23613.  ************************************************************************/
  23614.  
  23615.  VOID
  23616.  Paint(hps, fClearScreen)
  23617.  HPS  hps;
  23618.  BOOL fClearScreen;
  23619.  {
  23620.      LINEBUNDLE lb;
  23621.      RECTL rcl;
  23622.      if (fClearScreen)
  23623.      {
  23624.          /* clear the screen */
  23625.          WinQueryWindowRect(global.hwnd, &rcl);
  23626.          GpiBitBlt(hps, NULL, 2L, (PPOINTL) &rcl, ROP_ONE, 0L);
  23627.      }
  23628.  
  23629.  
  23630.      if (global.cptl > 0L)
  23631.      {
  23632.          if (global.fDisplayControlPoints)
  23633.          {
  23634.              if (fClearScreen)
  23635.                  /* draw all the control points */
  23636.                  DrawControlPoints(hps, global.cptl, global.pptl);
  23637.              else if (global.usPtGrabbed != -1)
  23638.                  /* draw just the control point that moved */
  23639.                  DrawControlPoints(hps, 1L, global.pptl+global.usPtGrabbed);
  23640.          }
  23641.  
  23642.          /* set mix mode to xor */
  23643.          lb.usMixMode = FM_XOR;
  23644.          GpiSetAttrs(hps, PRIM_LINE, LBB_MIX_MODE, 0L, &lb);
  23645.  
  23646.          /* draw the current primitives */
  23647.  
  23648.          if (global.flPrim & PRIM_POLYLINE)
  23649.          {
  23650.              lb.lColor = CLR_BROWN;
  23651.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  23652.              DrawPrimitive(hps, IDM_POLYLINE);
  23653.          }
  23654.  
  23655.          if (global.flPrim & PRIM_POLYFILLET)
  23656.          {
  23657.              lb.lColor = CLR_DARKCYAN;
  23658.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  23659.              DrawPrimitive(hps, IDM_POLYFILLET);
  23660.          }
  23661.  
  23662.          if (global.flPrim & PRIM_POLYSPLINE)
  23663.          {
  23664.              lb.lColor = CLR_DARKPINK;
  23665.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  23666.              DrawPrimitive(hps, IDM_POLYSPLINE);
  23667.          }
  23668.  
  23669.          if (global.flPrim & PRIM_POINTARC)
  23670.          {
  23671.              lb.lColor = CLR_BACKGROUND;
  23672.              GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  23673.              DrawPrimitive(hps, IDM_POINTARC);
  23674.          }
  23675.      }
  23676.  }
  23677.  
  23678.  
  23679.  
  23680.  
  23681.  /************************************************************************
  23682.  *
  23683.  *   DrawPrimitive
  23684.  *
  23685.  ************************************************************************/
  23686.  
  23687.  VOID
  23688.  DrawPrimitive(hps, usPrim)
  23689.  HPS hps;
  23690.  USHORT usPrim;
  23691.  {
  23692.      switch ( usPrim )
  23693.      {
  23694.      case IDM_POLYLINE:
  23695.          DrawPolyLine(hps);
  23696.          break;
  23697.  
  23698.      case IDM_POLYFILLET:
  23699.          DrawPolyFillet(hps);
  23700.          break;
  23701.  
  23702.      case IDM_POLYSPLINE:
  23703.          DrawPolySpline(hps);
  23704.          break;
  23705.  
  23706.      case IDM_POINTARC:
  23707.          DrawPointArc(hps);
  23708.          break;
  23709.      }
  23710.  }
  23711.  
  23712.  
  23713.  
  23714.  
  23715.  /************************************************************************
  23716.  *
  23717.  *   DrawPolyLine
  23718.  *
  23719.  ************************************************************************/
  23720.  
  23721.  VOID
  23722.  DrawPolyLine(hps)
  23723.  HPS hps;
  23724.  {
  23725.      GpiSetCurrentPosition( hps, global.pptl );
  23726.      GpiPolyLine( hps, global.cptl-1L, global.pptl+1 );
  23727.  }
  23728.  
  23729.  
  23730.  
  23731.  
  23732.  /************************************************************************
  23733.  *
  23734.  *   DrawPolyFillet
  23735.  *
  23736.  ************************************************************************/
  23737.  
  23738.  VOID
  23739.  DrawPolyFillet(hps)
  23740.  HPS hps;
  23741.  {
  23742.      if (global.cptl > 2)
  23743.      {
  23744.          GpiSetCurrentPosition( hps, global.pptl );
  23745.          GpiPolyFillet( hps, global.cptl-1L, global.pptl+1 );
  23746.      }
  23747.  }
  23748.  
  23749.  
  23750.  
  23751.  
  23752.  /************************************************************************
  23753.  *
  23754.  *   DrawPolySpline
  23755.  *
  23756.  ************************************************************************/
  23757.  
  23758.  VOID
  23759.  DrawPolySpline(hps)
  23760.  HPS hps;
  23761.  {
  23762.      USHORT cptSlack;        /* # points in pptl not usable by PolySpline */
  23763.  
  23764.      /* GpiPolySpline expects the number of points to be a
  23765.         multiple of 3.  If we have a non-multiple of three,
  23766.         (excluding the first point, which we've used to set
  23767.         the current position), only pass the largest multiple
  23768.         of three, saving the rest for the next go-round. */
  23769.  
  23770.      cptSlack = (int)((global.cptl-1L) % 3) + 1;
  23771.      GpiSetCurrentPosition( hps, global.pptl );
  23772.      GpiPolySpline( hps, global.cptl-cptSlack,
  23773.                     global.pptl+1 );
  23774.  }
  23775.  
  23776.  
  23777.  
  23778.  
  23779.  /************************************************************************
  23780.  *
  23781.  *   DrawPointArc
  23782.  *
  23783.  ************************************************************************/
  23784.  
  23785.  VOID
  23786.  DrawPointArc(hps)
  23787.  HPS hps;
  23788.  {
  23789.      if (global.cptl >= 3L)
  23790.      {
  23791.          GpiSetCurrentPosition( hps, global.pptl );
  23792.          GpiPointArc( hps, global.pptl+1 );
  23793.      }
  23794.  }
  23795.  
  23796.  
  23797.  
  23798.  
  23799.  /************************************************************************
  23800.  *
  23801.  *   DrawControlPoints
  23802.  *
  23803.  ************************************************************************/
  23804.  
  23805.  VOID
  23806.  DrawControlPoints(hps, cptl, pptl)
  23807.  HPS hps;
  23808.  LONG cptl;
  23809.  PPOINTL pptl;
  23810.  {
  23811.      MARKERBUNDLE mb;
  23812.  
  23813.      mb.lColor = CLR_TRUE;
  23814.      mb.usMixMode = FM_XOR;
  23815.      GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR | MBB_MIX_MODE, 0L, &mb);
  23816.  
  23817.      GpiPolyMarker(hps, cptl, pptl);
  23818.  }
  23819.  
  23820.  
  23821.  
  23822.  
  23823.  /************************************************************************
  23824.  *
  23825.  *   MyMessageBox
  23826.  *
  23827.  *   Displays a message box with the given string.  To simplify matters,
  23828.  *   the box will always have the same title ("PolyLine Editor"), will always
  23829.  *   have a single button ("Ok"), will always have an exclamation point
  23830.  *   icon, and will always be application modal.
  23831.  *
  23832.  ************************************************************************/
  23833.  
  23834.  VOID
  23835.  MyMessageBox(hWnd, sz)
  23836.  HWND hWnd;
  23837.  PSZ sz;
  23838.  {
  23839.      static char *szTitle = "PolyLine Editor";
  23840.  
  23841.      WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, 0,
  23842.                    MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
  23843.  }
  23844.  
  23845.  MRESULT CALLBACK AboutDlgProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  23846.  /*
  23847.      About... dialog procedure
  23848.  */
  23849.      switch(msg) {
  23850.          case WM_COMMAND:
  23851.              switch(COMMANDMSG(&msg)->cmd) {
  23852.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  23853.                  default: break;
  23854.              }
  23855.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  23856.      }
  23857.      return FALSE;
  23858.  }
  23859.  
  23860.  
  23861.  EXPAND.C
  23862.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\EXPAND\EXPAND.C
  23863.  
  23864.  #define INCL_PM
  23865.  #include <OS2.H>
  23866.  #include "Expand.H"
  23867.  
  23868.  MRESULT EXPENTRY WndProc      (HWND, USHORT, MPARAM, MPARAM );
  23869.  MRESULT EXPENTRY AboutDlgProc (HWND, USHORT, MPARAM, MPARAM);
  23870.  MRESULT EXPENTRY DialogProc  (HWND, USHORT, MPARAM, MPARAM);
  23871.  
  23872.  int cdecl main(void);
  23873.  
  23874.  char szAppName[] = "Expand";
  23875.  
  23876.  HAB        hAB;
  23877.  HMQ        hmqMsgQueue;
  23878.  HWND        hWndMain,
  23879.          hWndFrame;
  23880.  
  23881.  int cdecl main()
  23882.  {
  23883.      QMSG    qmsg;
  23884.      ULONG   ctlData;
  23885.  
  23886.      hAB = WinInitialize (0);
  23887.      hmqMsgQueue = WinCreateMsgQueue (hAB, 0);
  23888.  
  23889.      if (!WinRegisterClass (hAB,
  23890.                             szAppName,
  23891.                             WndProc,
  23892.                             CS_SYNCPAINT | CS_SIZEREDRAW,
  23893.                             0)) {
  23894.          return(0);
  23895.      }
  23896.  
  23897.  
  23898.      ctlData = FCF_STANDARD;
  23899.      hWndFrame = WinCreateStdWindow ( HWND_DESKTOP,
  23900.                                      WS_VISIBLE,
  23901.                                      &ctlData,
  23902.                                      szAppName,
  23903.                                      NULL,
  23904.                                      0L,
  23905.                                      0,
  23906.                                      ID_RESOURCE,
  23907.                                      &hWndMain);
  23908.      WinSetWindowText (hWndFrame, szAppName);
  23909.      WinShowWindow (hWndFrame, TRUE);
  23910.  
  23911.      while ( WinGetMsg (hAB, &qmsg, NULL, 0, 0)) {
  23912.          WinDispatchMsg (hAB, &qmsg);
  23913.      }
  23914.  
  23915.      WinDestroyWindow   (hWndFrame);
  23916.      WinDestroyMsgQueue (hmqMsgQueue);
  23917.      WinTerminate       (hAB);
  23918.  }
  23919.  
  23920.  MRESULT EXPENTRY WndProc (hWnd, msg, mp1, mp2)
  23921.      HWND    hWnd;
  23922.      USHORT  msg;
  23923.      MPARAM  mp1, mp2;
  23924.  {
  23925.      HPS    hPS;
  23926.      RECTL   rclPaint, rclWindow;
  23927.      POINTL  ptlPatternRef;
  23928.  
  23929.      switch (msg) {
  23930.  
  23931.          case WM_COMMAND:
  23932.              switch (COMMANDMSG(&msg)->cmd) {
  23933.                  case IDM_ABOUT:
  23934.                      WinDlgBox(HWND_DESKTOP, hWnd, AboutDlgProc,
  23935.                          (HMODULE) NULL, ID_RESOURCE, NULL);
  23936.                      break;
  23937.  
  23938.                  case IDM_ITEM+1:
  23939.                      WinDlgBox(HWND_DESKTOP, hWnd, DialogProc,
  23940.                          (HMODULE) NULL, ID_DIALOG, NULL);
  23941.                      break;
  23942.  
  23943.                  case IDM_ITEM+2:
  23944.                  case IDM_ITEM+3:
  23945.                  case IDM_ITEM+4:
  23946.                      break;
  23947.  
  23948.                  case IDM_EXIT:
  23949.                      WinPostMsg (hWnd, WM_CLOSE, 0L, 0L);
  23950.                      break;
  23951.              }
  23952.              break;
  23953.  
  23954.          case WM_HELP:
  23955.              WinMessageBox (HWND_DESKTOP, hWnd,
  23956.                  "Help Not Implemented Yet.",
  23957.                  " - Help - ",
  23958.                  0,
  23959.                  MB_OK | MB_MOVEABLE | MB_APPLMODAL);
  23960.              break;
  23961.  
  23962.          case WM_CLOSE:
  23963.              WinPostMsg (hWnd, WM_QUIT, 0L, 0L);
  23964.              break;
  23965.  
  23966.          case WM_PAINT:
  23967.              hPS = WinBeginPaint (hWnd, NULL, &rclPaint);
  23968.  
  23969.              WinQueryWindowRect(hWnd, &rclWindow);
  23970.              ptlPatternRef.x = rclWindow.xLeft;
  23971.              ptlPatternRef.y = rclWindow.yTop;
  23972.              GpiSetPatternRefPoint(hPS, &ptlPatternRef);
  23973.              WinFillRect(hPS, &rclPaint, SYSCLR_APPWORKSPACE);
  23974.  
  23975.              WinEndPaint (hPS);
  23976.              break;
  23977.  
  23978.          default:
  23979.              return (WinDefWindowProc (hWnd, msg, mp1, mp2));
  23980.      }
  23981.      return 0L;
  23982.  }
  23983.  
  23984.  
  23985.  MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  23986.  {
  23987.      switch (msg) {
  23988.          case WM_COMMAND:
  23989.              switch (COMMANDMSG(&msg)->cmd) {
  23990.                  case IDB_OK:
  23991.                      WinDismissDlg (hwnd, TRUE);
  23992.                      return 0;
  23993.              }
  23994.              break;
  23995.       }
  23996.       return WinDefDlgProc (hwnd, msg, mp1, mp2);
  23997.  }
  23998.  
  23999.  MRESULT EXPENTRY DialogProc (HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  24000.  {
  24001.      SWP  swpDlg, swpParent, swpOwner;
  24002.      static HWND option, button1, button2, button3, button4;
  24003.  
  24004.      switch (msg) {
  24005.  
  24006.          case WM_INITDLG:
  24007.              WinSendDlgItemMsg (hDlg, 256, EM_SETTEXTLIMIT, MPFROMSHORT(8), 0L
  24008.              WinQueryWindowPos (hDlg, &swpDlg);
  24009.              WinQueryWindowPos (WinQueryWindow(hDlg, QW_PARENT, FALSE), &swpPa
  24010.              WinQueryWindowPos (WinQueryWindow(hDlg, QW_OWNER, FALSE), &swpOwn
  24011.              swpDlg.x = swpOwner.x + ((swpOwner.cx / 2) - ((swpDlg.cx+120) / 2
  24012.              swpDlg.y = swpOwner.y + ((swpOwner.cy / 2) - (swpDlg.cy / 2));
  24013.              WinSetMultWindowPos (hAB, &swpDlg, 1);
  24014.              option  = WinWindowFromID (hDlg, IDB_OPTION);
  24015.              button1 = WinWindowFromID (hDlg, IDB_RADIO1);
  24016.              WinShowWindow (button1, FALSE);
  24017.              button2 = WinWindowFromID (hDlg, IDB_RADIO2);
  24018.              WinShowWindow (button2, FALSE);
  24019.              button3 = WinWindowFromID (hDlg, IDB_RADIO3);
  24020.              WinShowWindow (button3, FALSE);
  24021.              button4 = WinWindowFromID (hDlg, IDB_RADIO4);
  24022.              WinShowWindow (button4, FALSE);
  24023.              break;
  24024.  
  24025.          case WM_COMMAND:
  24026.              switch (COMMANDMSG(&msg)->cmd) {
  24027.                  case IDB_OPTION:
  24028.                      WinQueryWindowPos (hDlg, &swpDlg);
  24029.                      swpDlg.fs = SWP_SIZE;
  24030.                      swpDlg.cx += 120;
  24031.                      WinSetMultWindowPos (hAB, &swpDlg, 1);
  24032.                      WinEnableWindow (option, FALSE);
  24033.                      WinShowWindow (button1, TRUE);
  24034.                      WinShowWindow (button2, TRUE);
  24035.                      WinShowWindow (button3, TRUE);
  24036.                      WinShowWindow (button4, TRUE);
  24037.                      WinSetFocus (HWND_DESKTOP, button1);
  24038.                      return FALSE;
  24039.  
  24040.                  case IDB_OK:
  24041.                  case IDB_CANCEL:
  24042.                      WinDismissDlg (hDlg, TRUE);
  24043.                      return 0;
  24044.              }
  24045.              break;
  24046.       }
  24047.       return WinDefDlgProc (hDlg, msg, mp1, mp2);
  24048.  }
  24049.  
  24050.  
  24051.  FATPEL.C
  24052.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\FATPEL\FATPEL.C
  24053.  
  24054.  /************************************************************************
  24055.  *
  24056.  *   fatpel.c -- The Diamond Metric, Theory vs. Practice
  24057.  *
  24058.  *   Created by Microsoft Corporation, 1989
  24059.  *
  24060.  ************************************************************************/
  24061.  
  24062.  #define INCL_WINFRAMEMGR
  24063.  #define INCL_WINWINDOWMGR
  24064.  #define INCL_WINMESSAGEMGR
  24065.  #define        INCL_WINPOINTERS
  24066.  #define INCL_WINSWITCHLIST
  24067.  #define INCL_WINTRACKRECT
  24068.  #define INCL_WINDIALOGS
  24069.  #define INCL_WINBUTTONS
  24070.  #define INCL_GPILOGCOLORTABLE
  24071.  #define INCL_GPIBITMAPS
  24072.  #define        INCL_GPITRANSFORMS
  24073.  #define INCL_DOSMEMMGR
  24074.  #define INCL_DOSFILEMGR
  24075.  #define INCL_BITMAPFILEFORMAT
  24076.  #define INCL_GPIPRIMITIVES
  24077.  #define INCL_WINMENUS
  24078.  #define INCL_GPIREGIONS
  24079.  #define INCL_WINPOINTERS
  24080.  #define INCL_WININPUT
  24081.  #include <os2.h>
  24082.  
  24083.  #include <stdio.h>
  24084.  #include <stdlib.h>
  24085.  #include <string.h>
  24086.  
  24087.  #include "opendlg.h"
  24088.  #include "fatpel.h"
  24089.  
  24090.  
  24091.  
  24092.  
  24093.  /************************************************************************
  24094.  *
  24095.  *   Function declarations
  24096.  *
  24097.  ************************************************************************/
  24098.  
  24099.  /* Private functions */
  24100.  
  24101.  VOID  cdecl main(VOID);
  24102.  BOOL  FAR InitGlobals(VOID);
  24103.  BOOL  FAR InitApp(VOID);
  24104.  VOID  Close(HWND);
  24105.  VOID  Command(HWND, USHORT);
  24106.  VOID  Paint(HPS, USHORT);
  24107.  VOID  EraseBackground(HPS);
  24108.  VOID  DrawGrid(HPS);
  24109.  VOID  DisplayRenderedPels(HPS, USHORT);
  24110.  VOID  DisplayControlPoints(HPS, LONG, PPOINTL, USHORT);
  24111.  VOID  DisplayMathematicalObject(HPS, USHORT);
  24112.  VOID  DrawFatPels(HPS);
  24113.  VOID  DrawOneFatPel(HPS, PPOINTL, COLOR);
  24114.  VOID  GetFatPelFromPt(PPOINTL, PPOINTL);
  24115.  VOID  SetFatPel(PPOINTL, COLOR);
  24116.  VOID  RoundControlPoints(HPS, LONG, PPOINTL, PPOINTL, LONG, LONG);
  24117.  VOID  ComputeTransform(PRECTL, PRECTL);
  24118.  VOID  DrawPrimitive(HPS, LONG, PPOINTL);
  24119.  VOID  UpdateSurfaceDims(VOID);
  24120.  VOID  MySetWindowLong        (HWND, USHORT, LONG);
  24121.  VOID  MySetWindowLongHex(HWND, USHORT, LONG);
  24122.  LONG  MyGetWindowLong        (HWND, USHORT);
  24123.  VOID  MouseMove(HWND, MPARAM);
  24124.  VOID  ButtonUp(HWND, USHORT);
  24125.  VOID  ButtonDown(HWND, USHORT, MPARAM);
  24126.  VOID  DragPelSize(HWND, POINTS);
  24127.  VOID  WriteFile(HWND, HPS);
  24128.  BOOL  WriteBMP(HFILE, HPS, PBITMAPINFOHEADER);
  24129.  VOID  MyMessageBox(HWND, PSZ);
  24130.  VOID  SaveWindowToFile(HWND);
  24131.  SHORT IsPtInList(PPOINTL);
  24132.  SHORT AddPtToList(PPOINTL);
  24133.  BOOL  IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
  24134.  VOID  SwapLong(PLONG, PLONG);
  24135.  
  24136.  
  24137.  /* Exported functions */
  24138.  
  24139.  ULONG CALLBACK WndProc         (HWND, USHORT, MPARAM, MPARAM);
  24140.  ULONG CALLBACK AboutDlg  (HWND, USHORT, MPARAM, MPARAM);
  24141.  ULONG CALLBACK ColorsDlg (HWND, USHORT, MPARAM, MPARAM);
  24142.  ULONG CALLBACK PelSizeDlg(HWND, USHORT, MPARAM, MPARAM);
  24143.  
  24144.  
  24145.  
  24146.  
  24147.  /************************************************************************
  24148.  *
  24149.  *   Global Variables
  24150.  *
  24151.  ************************************************************************/
  24152.  
  24153.  /* compute absolute value for arbitrary (in my case, LONG) number */
  24154.  /* this is to avoid compiler warnings about data conversion */
  24155.  #define L_ABS(x)        (((x) > 0) ? (x) : (-(x)))
  24156.  
  24157.  typedef struct
  24158.  {
  24159.      HAB      hab;
  24160.      HMQ      hMsgQ;
  24161.      HWND     hwndFrame;
  24162.      HWND     hwnd;
  24163.  
  24164.      BOOL     fFirstTime;   /* TRUE --> first time initialization of rcl */
  24165.      RECTL    rcl;           /* dimensions of client rectangle */
  24166.  
  24167.      HPS      hpsFat;
  24168.      HDC      hdcFat;
  24169.      HBITMAP  hbmFat;
  24170.      HPS      hpsFatShadow;
  24171.      HDC      hdcFatShadow;
  24172.      HBITMAP  hbmFatShadow;
  24173.  
  24174.      RECTL    rclFatBM;           /* dimensions of fatbits bitmap */
  24175.      RECTL    rclFat;           /* dimensions of active fat bits grid */
  24176.      LONG     cxFatPel;            /* width of fat pel */
  24177.      LONG     cyFatPel;            /* height of fat pel */
  24178.      LONG     cxHalfFatPel;
  24179.      LONG     cyHalfFatPel;
  24180.      USHORT   usPelShape;
  24181.  
  24182.      MATRIXLF matlf;        /* goes from window coords to fatpel coords */
  24183.  
  24184.      BOOL     fRGB;           /* TRUE --> color mode is RGB */
  24185.      COLOR    clrMathObj;
  24186.      COLOR    clrRenderedObj;
  24187.      COLOR    clrField;
  24188.      COLOR    clrCrossHair;
  24189.      COLOR    clrInterstice;
  24190.      COLOR    clrControlPoints;
  24191.  
  24192.      COLOR    clrBlackIndex;
  24193.      COLOR    clrEditPel;
  24194.  
  24195.      USHORT   usControlPointSymbol;
  24196.  
  24197.      BOOL     fDisplayRenderedObj;
  24198.      BOOL     fDisplayMathObj;
  24199.      BOOL     fDisplayControlPoints;
  24200.      BOOL     fDisplayCrossHairs;
  24201.      BOOL     fDisplayPelBorder;
  24202.      BOOL     fRoundControlPoints;
  24203.      BOOL     fAutoRedraw;
  24204.      USHORT   usCurPrim;
  24205.      USHORT   usMix;
  24206.  
  24207.      LONG     cptl;
  24208.      PPOINTL  pptl;
  24209.      PPOINTL  pptlTmp;
  24210.  
  24211.      BOOL     fDraggingPelSize;
  24212.      HPOINTER hptrDragSize;
  24213.  
  24214.      BOOL     fDraggingPelColor;
  24215.      HPOINTER hptrDragColor;
  24216.  
  24217.      SHORT    sPtGrabbed;
  24218.      BOOL     fDraggingControlPoint;
  24219.      LONG     lHitPrecision;
  24220.  
  24221.      BOOL     fEditPelColors;
  24222.  
  24223.  } GLOBALDATA;
  24224.  GLOBALDATA global;
  24225.  
  24226.  
  24227.  
  24228.  
  24229.  /************************************************************************
  24230.  *
  24231.  *   main
  24232.  *
  24233.  *   WinInitialize resizes our ring 2 stack, among other things, so
  24234.  *   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
  24235.  *   us as a REAL PM app. (WINDOWAPI in .DEF file does also).
  24236.  *   Call a sub to register our window class and create a window.
  24237.  *   Loop over messages.  Exit cleanly.
  24238.  *
  24239.  ************************************************************************/
  24240.  
  24241.  VOID cdecl
  24242.  main()
  24243.  {
  24244.      QMSG qMsg;
  24245.      int iRet = 0;
  24246.  
  24247.  
  24248.      global.hab         = WinInitialize(0);
  24249.      global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
  24250.  
  24251.      if (InitApp())
  24252.          while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
  24253.              WinDispatchMsg( global.hab, (PQMSG)&qMsg );
  24254.      else
  24255.          iRet = -1;
  24256.  
  24257.      WinDestroyWindow( global.hwndFrame );
  24258.      WinDestroyMsgQueue( global.hMsgQ );
  24259.      WinTerminate( global.hab );
  24260.      DosExit(EXIT_PROCESS, iRet);
  24261.  }
  24262.  
  24263.  
  24264.  
  24265.  
  24266.  /****************************************************************************
  24267.  *
  24268.  *   InitGlobals
  24269.  *
  24270.  *   Initialize global variables.
  24271.  *
  24272.  ****************************************************************************/
  24273.  
  24274.  BOOL FAR
  24275.  InitGlobals()
  24276.  {
  24277.      global.fFirstTime                 = TRUE;
  24278.  
  24279.      global.rcl.xLeft                 = 0L;
  24280.      global.rcl.yBottom                 = 0L;
  24281.      global.rcl.xRight                 = 0L;
  24282.      global.rcl.yTop                 = 0L;
  24283.  
  24284.      global.hpsFat                 = NULL;
  24285.      global.hdcFat                 = NULL;
  24286.      global.hbmFat                 = NULL;
  24287.      global.hpsFatShadow          = NULL;
  24288.      global.hdcFatShadow          = NULL;
  24289.      global.hbmFatShadow          = NULL;
  24290.      global.rclFatBM.xLeft         = 0L;
  24291.      global.rclFatBM.yBottom         = 0L;
  24292.      global.rclFatBM.xRight         = 0L;
  24293.      global.rclFatBM.yTop         = 0L;
  24294.  
  24295.      global.cxFatPel                 = 32L;
  24296.      global.cyFatPel                 = 32L;
  24297.      global.cxHalfFatPel          = global.cxFatPel / 2L;
  24298.      global.cyHalfFatPel          = global.cyFatPel / 2L;
  24299.      global.usPelShape                 = IDD_CIRCLE;
  24300.  
  24301.      global.fRGB                  = FALSE;
  24302.      global.clrMathObj                 = CLR_BLUE;
  24303.      global.clrRenderedObj         = CLR_NEUTRAL;
  24304.      global.clrField                 = CLR_CYAN;
  24305.      global.clrCrossHair          = CLR_DARKCYAN;
  24306.      global.clrInterstice         = CLR_BACKGROUND;
  24307.      global.clrControlPoints         = CLR_YELLOW;
  24308.  
  24309.      global.clrBlackIndex         = CLR_ERROR;
  24310.      global.clrEditPel                 = CLR_ERROR;
  24311.  
  24312.      global.usControlPointSymbol  = MARKSYM_SOLIDDIAMOND;
  24313.  
  24314.      global.fDisplayRenderedObj         = TRUE;
  24315.      global.fDisplayMathObj         = TRUE;
  24316.      global.fDisplayControlPoints = TRUE;
  24317.      global.fDisplayCrossHairs         = TRUE;
  24318.      global.fDisplayPelBorder         = TRUE;
  24319.      global.fRoundControlPoints         = FALSE;
  24320.      global.fAutoRedraw                 = TRUE;
  24321.      global.usCurPrim                 = IDM_POLYLINE;
  24322.      global.usMix                 = FM_OVERPAINT;
  24323.  
  24324.      global.fDraggingPelSize         = FALSE;
  24325.      global.fDraggingPelColor         = FALSE;
  24326.      global.fDraggingControlPoint = FALSE;
  24327.      global.sPtGrabbed                 = NO_POINT;
  24328.      global.lHitPrecision         = 0L;
  24329.  
  24330.      global.fEditPelColors         = FALSE;
  24331.  
  24332.  
  24333.      global.cptl = 0L;
  24334.      global.pptl = NULL;
  24335.      if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  24336.                     ((PUSHORT)&global.pptl)+1, 0))
  24337.          return FALSE;
  24338.      global.pptlTmp = NULL;
  24339.      if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  24340.                     ((PUSHORT)&global.pptlTmp)+1, 0))
  24341.          return FALSE;
  24342.  
  24343.      return TRUE;
  24344.  }
  24345.  
  24346.  
  24347.  
  24348.  
  24349.  /****************************************************************************
  24350.  *
  24351.  *   InitApp
  24352.  *
  24353.  *   Register application window class and creates standard window.
  24354.  *
  24355.  ****************************************************************************/
  24356.  
  24357.  #define INIT_MENU_ITEM(val, var)     \
  24358.          TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
  24359.  
  24360.  BOOL FAR
  24361.  InitApp()
  24362.  {
  24363.      char szTitle[24];
  24364.      ULONG ctldata;
  24365.      PID pid;
  24366.      TID tid;
  24367.      HSWITCH hsw;
  24368.      static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
  24369.                               SWL_JUMPABLE, "FatPels", 0 };
  24370.  
  24371.      if (!InitGlobals())
  24372.          return FALSE;
  24373.  
  24374.  
  24375.      /*  Register Application Window Class  */
  24376.  
  24377.      WinLoadString( global.hab, (HMODULE) NULL, IDS_TITLE, sizeof(szTitle), (P
  24378.      if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
  24379.              CS_SIZEREDRAW, 0 ))
  24380.          return FALSE;
  24381.  
  24382.  
  24383.      /* Load the pointer to use when dragging pel size. */
  24384.      if (!(global.hptrDragSize = WinLoadPointer( HWND_DESKTOP, (HMODULE) NULL,
  24385.          return FALSE;
  24386.  
  24387.      /* Load the pointer to use when dragging pel color. */
  24388.      if (!(global.hptrDragColor = WinLoadPointer( HWND_DESKTOP, (HMODULE) NULL
  24389.          return FALSE;
  24390.  
  24391.  
  24392.      /* Create a window instance of class "FatPel" */
  24393.  
  24394.      ctldata = FCF_STANDARD &
  24395.       ~(ULONG)(FCF_ICON | FCF_ACCELTABLE | FCF_TASKLIST);
  24396.  
  24397.      if (global.hwndFrame = WinCreateStdWindow(
  24398.          HWND_DESKTOP,                   /* specify desktop as parent window
  24399.          WS_VISIBLE,                   /* window styles
  24400.          &ctldata,                   /* frame creation flags
  24401.          (PCH)szTitle,                   /* window class name
  24402.          (PCH)szTitle,                   /* name appearing in window caption
  24403.          0L,                           /*
  24404.          (HMODULE)NULL,                   /* use current executable module id
  24405.          IDR_FATPEL,                   /* menu id
  24406.          (HWND FAR *)&global.hwnd   /* window handle
  24407.          ))
  24408.      {
  24409.          INIT_MENU_ITEM(IDM_RENDEREDOBJ,         global.fDisplayRenderedObj);
  24410.          INIT_MENU_ITEM(IDM_MATHOBJ,         global.fDisplayMathObj);
  24411.          INIT_MENU_ITEM(IDM_CTLPOINTS,         global.fDisplayControlPoints);
  24412.          INIT_MENU_ITEM(IDM_CROSSHAIRS,         global.fDisplayCrossHairs);
  24413.          INIT_MENU_ITEM(IDM_PELBORDER,         global.fDisplayPelBorder);
  24414.          INIT_MENU_ITEM(IDM_ROUNDPOINTS,         global.fRoundControlPoints);
  24415.          INIT_MENU_ITEM(IDM_AUTOREDRAW,         global.fAutoRedraw);
  24416.          INIT_MENU_ITEM(IDM_EDITPELCOLORS, global.fEditPelColors);
  24417.  
  24418.          CHECK_MENU_ITEM(global.hwndFrame, global.usCurPrim);
  24419.  
  24420.  
  24421.          /* Add ourselves to the switch list. */
  24422.  
  24423.          WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
  24424.          swctl.hwnd        = global.hwndFrame;
  24425.          swctl.idProcess = pid;
  24426.          hsw = WinAddSwitchEntry(&swctl);
  24427.  
  24428.          return TRUE;
  24429.      }
  24430.      return FALSE;
  24431.  }
  24432.  
  24433.  
  24434.  
  24435.  
  24436.  /*************************************************************************
  24437.  *
  24438.  *   WndProc
  24439.  *
  24440.  *   Process messages for the window class.
  24441.  *
  24442.  ************************************************************************/
  24443.  
  24444.  ULONG CALLBACK
  24445.  WndProc( hwnd, usMsg, mp1, mp2 )
  24446.  HWND        hwnd;
  24447.  USHORT        usMsg;
  24448.  MPARAM  mp1;
  24449.  MPARAM  mp2;
  24450.  {
  24451.      switch (usMsg)
  24452.      {
  24453.      case WM_CLOSE:
  24454.          Close(hwnd);
  24455.          break;
  24456.  
  24457.      case WM_COMMAND:
  24458.          Command(hwnd, LOUSHORT(mp1));
  24459.          break;
  24460.  
  24461.      case WM_PAINT:
  24462.          {
  24463.              HPS   hps;
  24464.  
  24465.              if (global.fFirstTime)
  24466.              {
  24467.                  SIZEF sizfx;
  24468.  
  24469.                  hps = WinGetPS(hwnd);
  24470.                  GpiQueryMarkerBox(hps, &sizfx);
  24471.                  global.lHitPrecision = sizfx.cx / 0x20000L + 1L;
  24472.                  WinReleasePS(hps);
  24473.  
  24474.                  UpdateSurfaceDims();
  24475.                  global.fFirstTime = FALSE;
  24476.              }
  24477.  
  24478.              /* The small bitmap may have been resized since we last
  24479.               * painted, in which case it will have been initialized to
  24480.               * the field color.  Therefore, we will render the mathematical
  24481.               * object to make sure the right fatpels are there.
  24482.               */
  24483.              global.usMix = FM_OVERPAINT;
  24484.              hps = WinBeginPaint(global.hwnd, NULL, NULL);
  24485.              Paint(hps, CLEAR_BACKGROUND|RENDER_MATH_OBJ);
  24486.              WinEndPaint(hps);
  24487.          }
  24488.          break;
  24489.  
  24490.      case WM_BUTTON1DOWN:
  24491.      case WM_BUTTON2DOWN:
  24492.          ButtonDown(hwnd, usMsg, mp1);
  24493.          break;
  24494.  
  24495.      case WM_BUTTON1UP:
  24496.      case WM_BUTTON2UP:
  24497.          ButtonUp(hwnd, usMsg);
  24498.          break;
  24499.  
  24500.      case WM_MOUSEMOVE:
  24501.          MouseMove(hwnd, mp1);
  24502.          break;
  24503.  
  24504.      case WM_SIZE:
  24505.          UpdateSurfaceDims();
  24506.          return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  24507.          break;
  24508.  
  24509.      default:
  24510.          return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  24511.          break;
  24512.      }
  24513.  
  24514.      return FALSE;
  24515.  }
  24516.  
  24517.  
  24518.  
  24519.  
  24520.  /************************************************************************
  24521.  *
  24522.  *   MouseMove
  24523.  *
  24524.  ************************************************************************/
  24525.  
  24526.  VOID
  24527.  MouseMove(hwnd, mp1)
  24528.  HWND hwnd;
  24529.  MPARAM mp1;
  24530.  {
  24531.      POINTL ptl;
  24532.      HPS hps;
  24533.  
  24534.  
  24535.      /* make sure we still have our pointer */
  24536.      /* notice the hierarchy of pointer modes */
  24537.  
  24538.      if (global.fDraggingPelSize)
  24539.      {
  24540.          if (global.hptrDragSize)
  24541.              WinSetPointer(HWND_DESKTOP,global.hptrDragSize);
  24542.      }
  24543.      else if (global.fEditPelColors)
  24544.      {
  24545.          if (global.hptrDragColor)
  24546.              WinSetPointer(HWND_DESKTOP,global.hptrDragColor);
  24547.      }
  24548.      else
  24549.          WinSetPointer(HWND_DESKTOP,
  24550.                    WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
  24551.  
  24552.  
  24553.      if (global.fDraggingPelColor)
  24554.      {
  24555.          POINTL ptl, ptlFat;
  24556.          HPS hps;
  24557.  
  24558.  
  24559.          ptl.x = (LONG) LOUSHORT(mp1);
  24560.          ptl.y = (LONG) HIUSHORT(mp1);
  24561.  
  24562.          /* letting the point go negative causes overflow errors */
  24563.          if (ptl.x < 0)
  24564.              ptl.x = 0;
  24565.          if (ptl.y < 0)
  24566.              ptl.y = 0;
  24567.  
  24568.          GetFatPelFromPt(&ptl, &ptlFat);
  24569.          SetFatPel(&ptlFat, global.clrEditPel);
  24570.  
  24571.          hps = WinGetPS(hwnd);
  24572.          Paint(hps, OVERRIDE_RENDERED_OBJ);
  24573.          Paint(hps, IGNORED);        /* this call just copies fatpels to the s
  24574.          WinReleasePS(hps);
  24575.      }
  24576.      else if (global.fDraggingControlPoint)
  24577.      {
  24578.          ptl.x = (LONG) LOUSHORT(mp1);
  24579.          ptl.y = (LONG) HIUSHORT(mp1);
  24580.  
  24581.          /* letting the point go negative causes overflow errors */
  24582.          if (ptl.x < 0)
  24583.              ptl.x = 0;
  24584.          if (ptl.y < 0)
  24585.              ptl.y = 0;
  24586.  
  24587.          if (global.sPtGrabbed != NO_POINT)
  24588.          {
  24589.              hps = WinGetPS(hwnd);
  24590.              Paint(hps, OVERRIDE_RENDERED_OBJ);
  24591.  
  24592.              global.pptl[global.sPtGrabbed] = ptl;
  24593.  
  24594.              Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  24595.              WinReleasePS(hps);
  24596.          }
  24597.      }
  24598.  }
  24599.  
  24600.  
  24601.  
  24602.  
  24603.  /************************************************************************
  24604.  *
  24605.  *   ButtonUp
  24606.  *
  24607.  ************************************************************************/
  24608.  
  24609.  VOID
  24610.  ButtonUp(hwnd, usMsg)
  24611.  HWND hwnd;
  24612.  USHORT usMsg;
  24613.  {
  24614.      SHORT i;
  24615.      HPS hps;
  24616.  
  24617.  
  24618.      if (global.fDraggingPelColor)
  24619.      {
  24620.          global.fDraggingPelColor = FALSE;
  24621.          WinSetCapture(HWND_DESKTOP, NULL);
  24622.      }
  24623.      else if (global.fDraggingControlPoint)
  24624.      {
  24625.          global.fDraggingControlPoint = FALSE;
  24626.          WinSetCapture(HWND_DESKTOP, NULL);
  24627.          if (global.sPtGrabbed != NO_POINT)
  24628.          {
  24629.              if (usMsg == WM_BUTTON2UP)        /* remove point? */
  24630.              {
  24631.                  hps = WinGetPS(hwnd);
  24632.                  Paint(hps, OVERRIDE_RENDERED_OBJ);
  24633.  
  24634.                  /* squeeze out selected point */
  24635.                  if ((i = global.sPtGrabbed) < (SHORT)(global.cptl-1))
  24636.                      while (i < (SHORT)(global.cptl-1))
  24637.                      {
  24638.                          global.pptl[i] = global.pptl[i+1];
  24639.                          ++i;
  24640.                      }
  24641.  
  24642.                  --global.cptl;
  24643.                  global.sPtGrabbed = NO_POINT;
  24644.  
  24645.                  Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  24646.                  WinReleasePS(hps);
  24647.              }
  24648.              else    /* WM_BUTTON1UP */
  24649.                  global.sPtGrabbed = NO_POINT;
  24650.          }
  24651.      }
  24652.  }
  24653.  
  24654.  
  24655.  
  24656.  
  24657.  /************************************************************************
  24658.  *
  24659.  *   ButtonDown
  24660.  *
  24661.  ************************************************************************/
  24662.  
  24663.  VOID
  24664.  ButtonDown(hwnd, usMsg, mp1)
  24665.  HWND hwnd;
  24666.  USHORT usMsg;
  24667.  MPARAM mp1;
  24668.  {
  24669.      if (global.fDraggingPelSize)
  24670.      {
  24671.          POINTS pt;
  24672.          HPS hps;
  24673.  
  24674.          pt.x = LOUSHORT(mp1);
  24675.          pt.y = HIUSHORT(mp1);
  24676.          DragPelSize(hwnd, pt);
  24677.          global.fDraggingPelSize = FALSE;
  24678.  
  24679.          WinSetPointer(HWND_DESKTOP,
  24680.                        WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
  24681.  
  24682.          hps = WinGetPS(hwnd);
  24683.          global.usMix = FM_OVERPAINT;
  24684.          Paint(hps, CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  24685.          WinReleasePS(hps);
  24686.      }
  24687.      else if (global.fEditPelColors)
  24688.      {
  24689.          POINTL ptl, ptlFat;
  24690.          HPS hps;
  24691.  
  24692.          global.fDraggingPelColor = TRUE;
  24693.          WinSetCapture(HWND_DESKTOP, hwnd);
  24694.  
  24695.          ptl.x = (LONG) LOUSHORT(mp1);
  24696.          ptl.y = (LONG) HIUSHORT(mp1);
  24697.  
  24698.          if (global.usMix != FM_XOR)
  24699.          {
  24700.              hps = WinGetPS(hwnd);
  24701.              global.usMix = FM_XOR;
  24702.              Paint(hps, CLEAR_BACKGROUND);
  24703.              WinReleasePS(hps);
  24704.          }
  24705.  
  24706.          if (usMsg == WM_BUTTON1DOWN)
  24707.              global.clrEditPel = global.clrRenderedObj;
  24708.          else
  24709.              global.clrEditPel = global.clrField;
  24710.  
  24711.          GetFatPelFromPt(&ptl, &ptlFat);
  24712.          SetFatPel(&ptlFat, global.clrEditPel);
  24713.  
  24714.          hps = WinGetPS(hwnd);
  24715.          Paint(hps, OVERRIDE_RENDERED_OBJ);
  24716.          Paint(hps, IGNORED);        /* this call just copies fatpels to the s
  24717.          WinReleasePS(hps);
  24718.      }
  24719.      else if (!global.fDraggingControlPoint)
  24720.      {
  24721.          POINTL ptl;
  24722.          SHORT sNewPtGrabbed;
  24723.          HPS hps;
  24724.  
  24725.          global.fDraggingControlPoint = TRUE;
  24726.          WinSetCapture(HWND_DESKTOP, hwnd);
  24727.  
  24728.          ptl.x = (LONG) LOUSHORT(mp1);
  24729.          ptl.y = (LONG) HIUSHORT(mp1);
  24730.  
  24731.          sNewPtGrabbed = IsPtInList(&ptl);
  24732.  
  24733.          if (global.usMix != FM_XOR)
  24734.          {
  24735.              hps = WinGetPS(hwnd);
  24736.              global.usMix = FM_XOR;
  24737.              Paint(hps, CLEAR_BACKGROUND);
  24738.              WinReleasePS(hps);
  24739.          }
  24740.  
  24741.          if (usMsg == WM_BUTTON1DOWN)        /* add/move point? */
  24742.          {
  24743.              hps = WinGetPS(hwnd);
  24744.  
  24745.              if (sNewPtGrabbed != NO_POINT)
  24746.                  global.sPtGrabbed = sNewPtGrabbed;
  24747.              Paint(hps, OVERRIDE_RENDERED_OBJ);
  24748.  
  24749.              if (sNewPtGrabbed == NO_POINT)
  24750.                  global.sPtGrabbed = AddPtToList(&ptl);
  24751.              else
  24752.                  global.sPtGrabbed = sNewPtGrabbed;
  24753.  
  24754.              Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
  24755.              WinReleasePS(hps);
  24756.  
  24757.              if (global.sPtGrabbed == NO_POINT)
  24758.                  MyMessageBox(global.hwnd, "Cannot add any more points.");
  24759.          }
  24760.          else if (sNewPtGrabbed != NO_POINT)
  24761.              global.sPtGrabbed = sNewPtGrabbed;
  24762.      }
  24763.  }
  24764.  
  24765.  
  24766.  
  24767.  
  24768.  /************************************************************************
  24769.  *
  24770.  *   GetFatPelFromPt
  24771.  *
  24772.  ************************************************************************/
  24773.  
  24774.  VOID
  24775.  GetFatPelFromPt(pptl, pptlFat)
  24776.  PPOINTL pptl;
  24777.  PPOINTL pptlFat;
  24778.  {
  24779.      pptlFat->x = pptl->x / global.cxFatPel;
  24780.      pptlFat->y = pptl->y / global.cyFatPel;
  24781.  }
  24782.  
  24783.  
  24784.  
  24785.  
  24786.  /************************************************************************
  24787.  *
  24788.  *   SetFatPel
  24789.  *
  24790.  ************************************************************************/
  24791.  
  24792.  VOID
  24793.  SetFatPel(pptl, clr)
  24794.  PPOINTL pptl;
  24795.  COLOR clr;
  24796.  {
  24797.      LINEBUNDLE lb;
  24798.  
  24799.      if (global.hpsFat)
  24800.      {
  24801.          lb.lColor = clr;
  24802.          GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
  24803.          GpiSetPel(global.hpsFat, pptl);
  24804.      }
  24805.  }
  24806.  
  24807.  
  24808.  
  24809.  
  24810.  /************************************************************************
  24811.  *
  24812.  *   IsPtInList
  24813.  *
  24814.  ************************************************************************/
  24815.  
  24816.  SHORT
  24817.  IsPtInList(pptl)
  24818.  PPOINTL pptl;
  24819.  {
  24820.      SHORT i;
  24821.  
  24822.  
  24823.      /* try to find pptl in the points we already have */
  24824.      for (i = 0; i < (SHORT)global.cptl; ++i)
  24825.          if (((L_ABS(pptl->x - global.pptl[i].x)) <= global.lHitPrecision) &&
  24826.              ((L_ABS(pptl->y - global.pptl[i].y)) <= global.lHitPrecision))
  24827.                  return i;
  24828.  
  24829.      /* couldn't find it */
  24830.      return NO_POINT;
  24831.  }
  24832.  
  24833.  
  24834.  
  24835.  
  24836.  /************************************************************************
  24837.  *
  24838.  *   AddPtToList
  24839.  *
  24840.  ************************************************************************/
  24841.  
  24842.  SHORT
  24843.  AddPtToList(pptl)
  24844.  PPOINTL pptl;
  24845.  {
  24846.      SHORT i, j;
  24847.  
  24848.      if (global.cptl < CPTLMAX)
  24849.      {
  24850.          /* check for new points lying on a line segment */
  24851.          for (i = 0; i < (SHORT)(global.cptl-1L); ++i)
  24852.              if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
  24853.              {
  24854.                  /* insert point between endpoints of nearest line segment */
  24855.                  for (j = (SHORT)global.cptl; j > i+1; --j)
  24856.                      global.pptl[j] = global.pptl[j - 1];
  24857.                  global.pptl[i+1] = *pptl;
  24858.                  ++global.cptl;
  24859.                  return i+1;
  24860.              }
  24861.  
  24862.          /* append the point */
  24863.  
  24864.          i = (SHORT) global.cptl;
  24865.          global.pptl[i] = *pptl;
  24866.          ++global.cptl;
  24867.          return i;
  24868.      }
  24869.  
  24870.      return NO_POINT;
  24871.  }
  24872.  
  24873.  
  24874.  
  24875.  
  24876.  /************************************************************************
  24877.  *
  24878.  *   IsPtCloseToLine
  24879.  *
  24880.  ************************************************************************/
  24881.  
  24882.  BOOL
  24883.  IsPtCloseToLine(pptl1, pptl2, pptlTest)
  24884.  PPOINTL pptl1;
  24885.  PPOINTL pptl2;
  24886.  PPOINTL pptlTest;
  24887.  {
  24888.      POINTL ptlLL, ptlUR;
  24889.      LONG dx, dy, yIntercept, error;
  24890.      LONG lBoxAdjustment;
  24891.  
  24892.  
  24893.      /* find the bounding box of the line segment */
  24894.  
  24895.      ptlLL = *pptl1;        /* assume line goes lower left to upper right */
  24896.      ptlUR = *pptl2;
  24897.      if (pptl1->x > pptl2->x)
  24898.          SwapLong(&ptlLL.x, &ptlUR.x);
  24899.      if (pptl1->y > pptl2->y)
  24900.          SwapLong(&ptlLL.y, &ptlUR.y);
  24901.  
  24902.  
  24903.      /* adjust the bounding box if it's too narrow */
  24904.  
  24905.      lBoxAdjustment = global.lHitPrecision/2L;
  24906.  
  24907.      dx = pptl2->x - pptl1->x;
  24908.      if (L_ABS(dx) <= global.lHitPrecision)
  24909.      {
  24910.          ptlLL.x -= lBoxAdjustment;
  24911.          ptlUR.x += lBoxAdjustment;
  24912.      }
  24913.      dy = pptl2->y - pptl1->y;
  24914.      if (L_ABS(dy) <= global.lHitPrecision)
  24915.      {
  24916.          ptlLL.y -= lBoxAdjustment;
  24917.          ptlUR.y += lBoxAdjustment;
  24918.      }
  24919.  
  24920.  
  24921.      /* see if the test point is in the bounding box of the line segment */
  24922.  
  24923.      if ((pptlTest->x >= ptlLL.x) &&
  24924.          (pptlTest->x <= ptlUR.x) &&
  24925.          (pptlTest->y >= ptlLL.y) &&
  24926.          (pptlTest->y <= ptlUR.y))
  24927.      {
  24928.          /* test for special cases */
  24929.  
  24930.          if (dx == 0)        /* vertical line */
  24931.          {
  24932.              return (L_ABS(pptlTest->x - pptl1->x) <= global.lHitPrecision);
  24933.          }
  24934.  
  24935.          if (dy == 0)        /* horizontal line */
  24936.          {
  24937.              return (L_ABS(pptlTest->y - pptl1->y) <= global.lHitPrecision);
  24938.          }
  24939.  
  24940.  
  24941.          /* test for general case */
  24942.  
  24943.          yIntercept = pptl1->y - (pptl1->x * dy) / dx;
  24944.  
  24945.          error = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
  24946.          if (L_ABS(error) <= global.lHitPrecision)
  24947.              return TRUE;
  24948.      }
  24949.  
  24950.      return FALSE;
  24951.  }
  24952.  
  24953.  
  24954.  
  24955.  
  24956.  /************************************************************************
  24957.  *
  24958.  *   SwapLong
  24959.  *
  24960.  ************************************************************************/
  24961.  
  24962.  VOID
  24963.  SwapLong(pl1, pl2)
  24964.  PLONG pl1, pl2;
  24965.  {
  24966.      LONG lTmp;
  24967.  
  24968.      lTmp = *pl1;
  24969.      *pl1 = *pl2;
  24970.      *pl2 = lTmp;
  24971.  }
  24972.  
  24973.  
  24974.  
  24975.  
  24976.  /************************************************************************
  24977.  *
  24978.  *   DragPelSize
  24979.  *
  24980.  *   Set the dimensions of a fat pel by dragging a rectangle
  24981.  *   on the screen.
  24982.  *
  24983.  ************************************************************************/
  24984.  
  24985.  VOID
  24986.  DragPelSize(hwnd, pt)
  24987.  HWND hwnd;
  24988.  POINTS pt;
  24989.  {
  24990.      TRACKINFO ti;
  24991.  
  24992.      WinSendMsg(global.hwndFrame, WM_QUERYTRACKINFO, (MPARAM)TF_MOVE, (MPARAM)
  24993.  
  24994.      ti.cxBorder   = 1;
  24995.      ti.cyBorder   = 1;
  24996.      ti.rclTrack.xLeft        = (LONG)pt.x;
  24997.      ti.rclTrack.yBottom = (LONG)pt.y;
  24998.      ti.rclTrack.xRight        = (LONG)pt.x;
  24999.      ti.rclTrack.yTop        = (LONG)pt.y;
  25000.      ti.fs = TF_RIGHT | TF_TOP;
  25001.      ti.ptlMinTrackSize.x = 1L;
  25002.      ti.ptlMinTrackSize.y = 1L;
  25003.  
  25004.      if (WinTrackRect(hwnd, NULL, &ti))
  25005.      {
  25006.          global.cxFatPel = (ti.rclTrack.xRight - ti.rclTrack.xLeft)  ;
  25007.          global.cyFatPel = (ti.rclTrack.yTop   - ti.rclTrack.yBottom);
  25008.  
  25009.          if (global.cxFatPel < 1L)
  25010.              global.cxFatPel = 1L;
  25011.  
  25012.          if (global.cyFatPel < 1L)
  25013.              global.cyFatPel = 1L;
  25014.  
  25015.          global.cxHalfFatPel = global.cxFatPel / 2L;
  25016.          global.cyHalfFatPel = global.cyFatPel / 2L;
  25017.  
  25018.          UpdateSurfaceDims();
  25019.      }
  25020.  }
  25021.  
  25022.  
  25023.  
  25024.  
  25025.  /************************************************************************
  25026.  *
  25027.  *   Close
  25028.  *
  25029.  ************************************************************************/
  25030.  
  25031.  VOID
  25032.  Close(hwnd)
  25033.  HWND hwnd;
  25034.  {
  25035.      if (global.hptrDragSize)
  25036.          WinDestroyPointer(global.hptrDragSize);
  25037.      WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  25038.  }
  25039.  
  25040.  
  25041.  
  25042.  
  25043.  /************************************************************************
  25044.  *
  25045.  *   Command
  25046.  *
  25047.  *   Dispatches menu commands to the proper handlers.
  25048.  *
  25049.  ************************************************************************/
  25050.  
  25051.  #define UPDATE_MENU_BOOL(var, val)                                \
  25052.          {                                                        \
  25053.              TOGGLE_BOOL((var));                                 \
  25054.              TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var));        \
  25055.          }
  25056.  
  25057.  #define UPDATE_MENU_LIST(var, val)                                \
  25058.          {                                                        \
  25059.              UNCHECK_MENU_ITEM(global.hwndFrame, (var));         \
  25060.              (var) = (val);                                        \
  25061.              CHECK_MENU_ITEM(global.hwndFrame, (var));                \
  25062.          }
  25063.  
  25064.  VOID
  25065.  Command(hwnd, id)
  25066.  HWND hwnd;
  25067.  USHORT id;
  25068.  {
  25069.      BOOL fRedraw = FALSE;
  25070.      USHORT fsCmd = IGNORED;
  25071.  
  25072.  
  25073.      switch (id)
  25074.      {
  25075.      case IDM_SAVE:
  25076.          SaveWindowToFile(hwnd);
  25077.          break;
  25078.  
  25079.      case IDM_ABOUT:
  25080.          WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)AboutDlg, (HMODULE) NULL,
  25081.                         IDR_ABOUTDLG, NULL );
  25082.          break;
  25083.  
  25084.      case IDM_REDRAW:
  25085.          fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  25086.          break;
  25087.  
  25088.      case IDM_SETPELSIZE:
  25089.          {
  25090.              LONG cxFatPel, cyFatPel;
  25091.  
  25092.              cxFatPel = global.cxFatPel;
  25093.              cyFatPel = global.cyFatPel;
  25094.  
  25095.              if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)PelSizeDlg, (HMODULE) N
  25096.                             IDR_PELSIZEDLG, NULL ))
  25097.              {
  25098.                  if ((cxFatPel == global.cxFatPel) &&
  25099.                      (cyFatPel == global.cyFatPel))
  25100.                      fsCmd = CLEAR_BACKGROUND;
  25101.                  else
  25102.                      fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ
  25103.                  fRedraw = TRUE;
  25104.              }
  25105.          }
  25106.          break;
  25107.  
  25108.      case IDM_DRAGPELSIZE:
  25109.          global.fDraggingPelSize = TRUE;
  25110.          break;
  25111.  
  25112.      case IDM_RENDEREDOBJ:
  25113.          UPDATE_MENU_BOOL(global.fDisplayRenderedObj, IDM_RENDEREDOBJ);
  25114.          fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  25115.          fRedraw = TRUE;
  25116.          break;
  25117.  
  25118.      case IDM_MATHOBJ:
  25119.          UPDATE_MENU_BOOL(global.fDisplayMathObj, IDM_MATHOBJ);
  25120.          fsCmd = CLEAR_BACKGROUND;
  25121.          fRedraw = TRUE;
  25122.          break;
  25123.  
  25124.      case IDM_CTLPOINTS:
  25125.          UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
  25126.          fsCmd = CLEAR_BACKGROUND;
  25127.          fRedraw = TRUE;
  25128.          break;
  25129.  
  25130.      case IDM_CROSSHAIRS:
  25131.          UPDATE_MENU_BOOL(global.fDisplayCrossHairs, IDM_CROSSHAIRS);
  25132.          fsCmd = CLEAR_BACKGROUND;
  25133.          fRedraw = TRUE;
  25134.          break;
  25135.  
  25136.      case IDM_PELBORDER:
  25137.          UPDATE_MENU_BOOL(global.fDisplayPelBorder, IDM_PELBORDER);
  25138.          fsCmd = CLEAR_BACKGROUND;
  25139.          fRedraw = TRUE;
  25140.          break;
  25141.  
  25142.      case IDM_ROUNDPOINTS:
  25143.          UPDATE_MENU_BOOL(global.fRoundControlPoints, IDM_ROUNDPOINTS);
  25144.          fsCmd = CLEAR_BACKGROUND;
  25145.          fRedraw = TRUE;
  25146.          break;
  25147.  
  25148.      case IDM_AUTOREDRAW:
  25149.          UPDATE_MENU_BOOL(global.fAutoRedraw, IDM_AUTOREDRAW);
  25150.          break;
  25151.  
  25152.      case IDM_NOPRIM:
  25153.      case IDM_POLYLINE:
  25154.      case IDM_POLYFILLET:
  25155.      case IDM_POLYSPLINE:
  25156.      case IDM_POINTARC:
  25157.          UPDATE_MENU_LIST(global.usCurPrim, id);
  25158.          fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  25159.          fRedraw = TRUE;
  25160.          break;
  25161.  
  25162.      case IDM_SETCOLORS:
  25163.          if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)ColorsDlg, (HMODULE) NULL,
  25164.                         IDR_COLORSDLG, NULL ))
  25165.          {
  25166.              fsCmd = CLEAR_BACKGROUND|RENDER_MATH_OBJ;
  25167.              fRedraw = TRUE;
  25168.          }
  25169.          break;
  25170.  
  25171.      case IDM_EDITPELCOLORS:
  25172.          UPDATE_MENU_BOOL(global.fEditPelColors, IDM_EDITPELCOLORS);
  25173.          break;
  25174.  
  25175.      case IDM_CLEARALL:
  25176.          global.cptl = 0L;
  25177.          fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
  25178.          fRedraw = TRUE;
  25179.          break;
  25180.      }
  25181.  
  25182.      if ((global.fAutoRedraw && fRedraw) || (id == IDM_REDRAW))
  25183.      {
  25184.          HPS hps;
  25185.  
  25186.          hps = WinGetPS(hwnd);
  25187.          global.usMix = FM_OVERPAINT;
  25188.          Paint(hps, fsCmd);
  25189.          WinReleasePS(hps);
  25190.      }
  25191.  }
  25192.  
  25193.  
  25194.  
  25195.  
  25196.  /************************************************************************
  25197.  *
  25198.  *   Paint
  25199.  *
  25200.  ************************************************************************/
  25201.  
  25202.  VOID
  25203.  Paint(hps, fsCmd)
  25204.  HPS  hps;
  25205.  USHORT fsCmd;
  25206.  {
  25207.      HRGN hrgn, hrgnClipOld, hrgnT;
  25208.  
  25209.  
  25210.      /* Clear the unused part of the client rectangle to a hatch pattern. */
  25211.      if (fsCmd & CLEAR_BACKGROUND)
  25212.          EraseBackground(hps);
  25213.  
  25214.  
  25215.      /* Set up the color mode as the user has requested */
  25216.  
  25217.      if (global.fRGB)
  25218.      {
  25219.          GpiCreateLogColorTable(hps, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
  25220.          if (global.hpsFat)
  25221.          {
  25222.              GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_RGB, 0L,
  25223.              GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_RGB
  25224.          }
  25225.      }
  25226.      else
  25227.          if (global.hpsFat)
  25228.          {
  25229.              GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_INDRGB, 0
  25230.              GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_IND
  25231.              global.clrBlackIndex = GpiQueryColorIndex(hps, 0L, 0x000000L);
  25232.          }
  25233.  
  25234.  
  25235.      if (global.usPelShape == IDD_CIRCLE)
  25236.      {
  25237.          ARCPARAMS arcp;
  25238.  
  25239.          arcp.lP = global.cxFatPel / 2L;
  25240.          arcp.lQ = global.cyFatPel / 2L;
  25241.          arcp.lR = 0L;
  25242.          arcp.lS = 0L;
  25243.  
  25244.          GpiSetArcParams(hps, &arcp);
  25245.      }
  25246.  
  25247.  
  25248.      /* set clipping rectangle to the fatbit surface */
  25249.  
  25250.      if ((hrgn = GpiCreateRegion(hps, 1L, &global.rcl)) != HRGN_ERROR)
  25251.          GpiSetClipRegion(hps, hrgn, &hrgnClipOld);
  25252.  
  25253.  
  25254.      if (fsCmd & CLEAR_BACKGROUND)
  25255.      {
  25256.          DrawGrid(hps);
  25257.  
  25258.          if (global.hpsFatShadow)
  25259.          {
  25260.              AREABUNDLE ab;
  25261.  
  25262.              /* clear shadow fatpel surface to background color */
  25263.              ab.lColor = global.clrField;
  25264.              GpiSetAttrs(global.hpsFatShadow, PRIM_AREA, ABB_COLOR, 0L, &ab);
  25265.              GpiBitBlt(global.hpsFatShadow, NULL, 2L, (PPOINTL)&global.rclFat,
  25266.          }
  25267.      }
  25268.  
  25269.      if (global.fDisplayRenderedObj && !(fsCmd & OVERRIDE_RENDERED_OBJ))
  25270.          DisplayRenderedPels(hps, fsCmd);
  25271.  
  25272.      if (global.fDisplayControlPoints)
  25273.      {
  25274.          /* when rubberbanding with the rendered obj, newly drawn fatpels
  25275.           * can wipe out stationary control point markers, so we have to
  25276.           * redraw them all each time
  25277.           */
  25278.  
  25279.          if (global.fDisplayRenderedObj || (fsCmd & CLEAR_BACKGROUND))
  25280.              DisplayControlPoints(hps, global.cptl, global.pptl, global.usMix)
  25281.          else if (global.sPtGrabbed != NO_POINT)
  25282.              /* draw just the control point that moved */
  25283.              DisplayControlPoints(hps, 1L, global.pptl+global.sPtGrabbed, glob
  25284.      }
  25285.  
  25286.      if (global.fDisplayMathObj)
  25287.          DisplayMathematicalObject(hps, global.usMix);
  25288.  
  25289.      /* delete the clip region we set up */
  25290.  
  25291.      if (hrgnClipOld != HRGN_ERROR)
  25292.          GpiSetClipRegion(hps, hrgnClipOld, &hrgnT);
  25293.      if (hrgn != HRGN_ERROR)
  25294.          GpiDestroyRegion(hps, hrgn);
  25295.  }
  25296.  
  25297.  
  25298.  
  25299.  
  25300.  /************************************************************************
  25301.  *
  25302.  *   DisplayMathematicalObject
  25303.  *
  25304.  ************************************************************************/
  25305.  
  25306.  VOID
  25307.  DisplayMathematicalObject(hps, usMix)
  25308.  HPS hps;
  25309.  USHORT usMix;
  25310.  {
  25311.      PPOINTL pptl;
  25312.      LINEBUNDLE lb;
  25313.  
  25314.      if (global.cptl > 0)
  25315.      {
  25316.          if (global.fRoundControlPoints)
  25317.          {
  25318.              RoundControlPoints(hps, global.cptl, global.pptl, global.pptlTmp,
  25319.                                 global.cxFatPel, global.cyFatPel);
  25320.              pptl = global.pptlTmp;
  25321.          }
  25322.          else
  25323.              pptl = global.pptl;
  25324.  
  25325.          /* draw line */
  25326.          lb.lColor    = global.clrMathObj;
  25327.          lb.usMixMode = usMix;
  25328.          GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR|LBB_MIX_MODE, 0L, &lb);
  25329.          DrawPrimitive(hps, global.cptl, pptl);
  25330.      }
  25331.  }
  25332.  
  25333.  
  25334.  
  25335.  
  25336.  /************************************************************************
  25337.  *
  25338.  *   DisplayControlPoints
  25339.  *
  25340.  ************************************************************************/
  25341.  
  25342.  VOID
  25343.  DisplayControlPoints(hps, cptl, pptl, usMix)
  25344.  HPS hps;
  25345.  LONG cptl;
  25346.  PPOINTL pptl;
  25347.  USHORT usMix;
  25348.  {
  25349.      PPOINTL pptlT;
  25350.      MARKERBUNDLE mb;
  25351.  
  25352.      if (cptl > 0)
  25353.      {
  25354.          if (global.fRoundControlPoints)
  25355.          {
  25356.              RoundControlPoints(hps, cptl, pptl, global.pptlTmp,
  25357.                                 global.cxFatPel, global.cyFatPel);
  25358.              pptlT = global.pptlTmp;
  25359.          }
  25360.          else
  25361.              pptlT = pptl;
  25362.  
  25363.  
  25364.          mb.lColor    = global.clrControlPoints;
  25365.          mb.usMixMode = usMix;
  25366.          mb.usSymbol  = global.usControlPointSymbol;
  25367.          GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR|MBB_MIX_MODE|MBB_SYMBOL, 0L,
  25368.  
  25369.          GpiPolyMarker(hps, cptl, pptlT);
  25370.      }
  25371.  }
  25372.  
  25373.  
  25374.  
  25375.  
  25376.  /************************************************************************
  25377.  *
  25378.  *   EraseBackground
  25379.  *
  25380.  *   Erase the unused part of the window to a hatch pattern.
  25381.  *
  25382.  ************************************************************************/
  25383.  
  25384.  VOID
  25385.  EraseBackground(hps)
  25386.  HPS hps;
  25387.  {
  25388.      RECTL rclClient, rclT;
  25389.      AREABUNDLE ab;
  25390.  
  25391.  
  25392.      WinQueryWindowRect(global.hwnd, &rclClient);
  25393.  
  25394.      ab.lColor          = CLR_BLACK;
  25395.      ab.lBackColor = CLR_WHITE;
  25396.      ab.usSymbol   = PATSYM_DIAG1;
  25397.      GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR|ABB_BACK_COLOR|ABB_SYMBOL,
  25398.                  0L, (PBUNDLE)&ab);
  25399.  
  25400.      if (global.rcl.yTop < rclClient.yTop)
  25401.      {
  25402.          rclT.xLeft   = rclClient.xLeft;
  25403.          rclT.yBottom = global.rcl.yBottom;
  25404.          rclT.xRight  = rclClient.xRight;
  25405.          rclT.yTop    = rclClient.yTop;
  25406.          GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, (ULONG) 0);
  25407.      }
  25408.  
  25409.      if (global.rcl.xRight < rclClient.xRight)
  25410.      {
  25411.          rclT.xLeft   = global.rcl.xRight;
  25412.          rclT.yBottom = rclClient.yBottom;
  25413.          rclT.xRight  = rclClient.xRight;
  25414.          rclT.yTop    = global.rcl.yTop;
  25415.          GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, (ULONG) 0);
  25416.      }
  25417.  
  25418.      ab.usSymbol   = PATSYM_SOLID;
  25419.      GpiSetAttrs(hps, PRIM_AREA, ABB_SYMBOL, 0L, (PBUNDLE)&ab);
  25420.  }
  25421.  
  25422.  
  25423.  
  25424.  
  25425.  /************************************************************************
  25426.  *
  25427.  *   DrawGrid
  25428.  *
  25429.  ************************************************************************/
  25430.  
  25431.  VOID
  25432.  DrawGrid(hps)
  25433.  HPS  hps;
  25434.  {
  25435.      AREABUNDLE ab;
  25436.      POINTL ptl;
  25437.      POINTL aptl[3];
  25438.  
  25439.  
  25440.      /* clear fatpel surface to background color */
  25441.      ab.lColor = global.clrInterstice;
  25442.      GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
  25443.      GpiBitBlt(hps, NULL, 2L, (PPOINTL)&global.rcl, ROP_PATCOPY, (ULONG) 0);
  25444.  
  25445.  
  25446.      /* draw one pel in lower left corner */
  25447.  
  25448.      ptl.x = global.cxFatPel / 2L;
  25449.      ptl.y = global.cyFatPel / 2L;
  25450.      DrawOneFatPel(hps, &ptl, global.clrField);
  25451.  
  25452.  
  25453.      /* blt up first column then across -- we don't have to worry
  25454.       * about the edges because a clip region has been setup to do that.
  25455.       */
  25456.  
  25457.      aptl[0].x = 0L;
  25458.      aptl[0].y = global.cyFatPel;
  25459.      aptl[1].x = global.cxFatPel;
  25460.      aptl[2].x = 0L;
  25461.      aptl[2].y = 0L;
  25462.  
  25463.      while (aptl[0].y <= global.rcl.yTop)
  25464.      {
  25465.          aptl[1].y  = aptl[0].y + aptl[0].y;
  25466.          GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
  25467.          aptl[0].y += aptl[1].y - aptl[0].y;
  25468.      }
  25469.  
  25470.      aptl[0].x = global.cxFatPel;
  25471.      aptl[0].y = 0L;
  25472.      aptl[1].y = global.rcl.yTop;
  25473.      aptl[2].x = 0L;
  25474.      aptl[2].y = 0L;
  25475.  
  25476.      while (aptl[0].x <= global.rcl.xRight)
  25477.      {
  25478.          aptl[1].x  = aptl[0].x + aptl[0].x;
  25479.          GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
  25480.          aptl[0].x += aptl[1].x - aptl[0].x;
  25481.      }
  25482.  }
  25483.  
  25484.  
  25485.  
  25486.  
  25487.  /************************************************************************
  25488.  *
  25489.  *   DisplayRenderedPels
  25490.  *
  25491.  ************************************************************************/
  25492.  
  25493.  VOID
  25494.  DisplayRenderedPels(hps, fsCmd)
  25495.  HPS hps;
  25496.  USHORT fsCmd;
  25497.  {
  25498.      LINEBUNDLE lb;
  25499.      AREABUNDLE ab;
  25500.      POINTL aptl[3];
  25501.  
  25502.      /*        Call GPI to draw the current primitive into the small bitmap,
  25503.       *        then fatbit it to the display.
  25504.       */
  25505.  
  25506.      if (global.hbmFat)
  25507.      {
  25508.          if (fsCmd & CLEAR_FAT_BITMAP)
  25509.          {
  25510.              /* clear fatpel surface to background color */
  25511.              ab.lColor = global.clrField;
  25512.              GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
  25513.              GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_P
  25514.          }
  25515.  
  25516.          if (fsCmd & RENDER_MATH_OBJ)
  25517.          {
  25518.              if (global.cptl > 0)
  25519.              {
  25520.                  /* draw line */
  25521.                  lb.lColor = global.clrRenderedObj;
  25522.                  GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
  25523.                  GpiSetModelTransformMatrix(global.hpsFat, 9L,
  25524.                                            &global.matlf, TRANSFORM_REPLACE);
  25525.                  DrawPrimitive(global.hpsFat, global.cptl, global.pptl);
  25526.                  GpiSetModelTransformMatrix(global.hpsFat, 0L, NULL, TRANSFORM
  25527.              }
  25528.          }
  25529.  
  25530.          /* xor the new rendered bitmap into the shadow bitmap */
  25531.          *((PRECTL)&aptl[0]) = global.rclFat;
  25532.          aptl[2].x = 0L;
  25533.          aptl[2].y = 0L;
  25534.          GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCINVERT
  25535.  
  25536.          /* fatbit object to the display */
  25537.          DrawFatPels(hps);
  25538.  
  25539.          /* get the new shadow bitmap */
  25540.          GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCCOPY,
  25541.      }
  25542.  }
  25543.  
  25544.  
  25545.  
  25546.  
  25547.  /************************************************************************
  25548.  *
  25549.  *   DrawFatPels
  25550.  *
  25551.  ************************************************************************/
  25552.  
  25553.  VOID
  25554.  DrawFatPels(hps)
  25555.  HPS hps;
  25556.  {
  25557.      POINTL ptl, ptlCenter;
  25558.      LONG i, j;
  25559.      COLOR clr;
  25560.  
  25561.  
  25562.      /* if the pel size is 1,1, then just blt the small bitmap to the
  25563.       * display.
  25564.       */
  25565.  
  25566.      if ((global.cxFatPel == 1L) && (global.cyFatPel == 1L))
  25567.      {
  25568.          POINTL aptl[3];
  25569.  
  25570.          *((PRECTL)&aptl[0]) = global.rcl;
  25571.          aptl[2].x = 0L;
  25572.          aptl[2].y = 0L;
  25573.          GpiBitBlt(hps, global.hpsFat, 3L, aptl, ROP_SRCCOPY, 0L);
  25574.  
  25575.          return;
  25576.      }
  25577.  
  25578.      for (i = 0; i < global.rclFat.xRight; ++i)
  25579.          for (j = 0; j < global.rclFat.yTop; ++j)
  25580.          {
  25581.              ptl.x = i;
  25582.              ptl.y = j;
  25583.  
  25584.              clr = GpiQueryPel(global.hpsFatShadow, &ptl);
  25585.              if ((global.fRGB && (clr != 0x000000L)) ||
  25586.                 (!global.fRGB && (clr != global.clrBlackIndex)))
  25587.              {
  25588.                  clr = GpiQueryPel(global.hpsFat, &ptl);
  25589.                  ptlCenter.x = (i * global.cxFatPel) + global.cxHalfFatPel;
  25590.                  ptlCenter.y = (j * global.cyFatPel) + global.cyHalfFatPel;
  25591.                  DrawOneFatPel(hps, &ptlCenter, clr);
  25592.              }
  25593.          }
  25594.  }
  25595.  
  25596.  
  25597.  
  25598.  
  25599.  /************************************************************************
  25600.  *
  25601.  *   DrawOneFatPel
  25602.  *
  25603.  ************************************************************************/
  25604.  
  25605.  VOID
  25606.  DrawOneFatPel(hps, pptl, clr)
  25607.  HPS hps;
  25608.  PPOINTL pptl;
  25609.  COLOR clr;
  25610.  {
  25611.      POINTL ptl;
  25612.      LINEBUNDLE lb;
  25613.      AREABUNDLE ab;
  25614.  
  25615.  
  25616.      if (global.fDisplayPelBorder || global.fDisplayCrossHairs)
  25617.      {
  25618.          lb.lColor = global.clrCrossHair;
  25619.          GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  25620.      }
  25621.  
  25622.      ab.lColor = clr;
  25623.      GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
  25624.  
  25625.  
  25626.      switch (global.usPelShape)
  25627.      {
  25628.      case IDD_SQUARE:
  25629.          {
  25630.              POINTL ptlT;
  25631.              ULONG flCmd;
  25632.  
  25633.              if (global.fDisplayPelBorder)
  25634.                  flCmd = DRO_OUTLINEFILL;
  25635.              else
  25636.                  flCmd = DRO_FILL;
  25637.  
  25638.              ptlT.x = pptl->x - global.cxHalfFatPel;
  25639.              ptlT.y = pptl->y - global.cyHalfFatPel;
  25640.              GpiSetCurrentPosition(hps, &ptlT);
  25641.              ptlT.x = pptl->x + global.cxHalfFatPel;
  25642.              ptlT.y = pptl->y + global.cyHalfFatPel;
  25643.              GpiBox(hps, flCmd, &ptlT, 0L, 0L);
  25644.          }
  25645.          break;
  25646.  
  25647.      case IDD_DIAMOND:
  25648.          {
  25649.              POINTL aptlT[4];
  25650.              ULONG flCmd;
  25651.  
  25652.              if (global.fDisplayPelBorder)
  25653.                  flCmd = BA_BOUNDARY;
  25654.              else
  25655.                  flCmd = 0L;
  25656.  
  25657.              aptlT[0].x = pptl->x;
  25658.              aptlT[0].y = pptl->y - global.cyHalfFatPel;
  25659.              aptlT[1].x = pptl->x - global.cxHalfFatPel;
  25660.              aptlT[1].y = pptl->y;
  25661.              aptlT[2].x = pptl->x;
  25662.              aptlT[2].y = pptl->y + global.cyHalfFatPel;
  25663.              aptlT[3].x = pptl->x + global.cxHalfFatPel;
  25664.              aptlT[3].y = pptl->y;
  25665.  
  25666.              GpiSetCurrentPosition(hps, &aptlT[3]);
  25667.              GpiBeginArea(hps, flCmd);
  25668.              GpiPolyLine(hps, 4L, aptlT);
  25669.              GpiEndArea(hps);
  25670.          }
  25671.  
  25672.          break;
  25673.  
  25674.      case IDD_CIRCLE:
  25675.          {
  25676.              ULONG flCmd;
  25677.  
  25678.              if (global.fDisplayPelBorder)
  25679.                  flCmd = DRO_OUTLINEFILL;
  25680.              else
  25681.                  flCmd = DRO_FILL;
  25682.  
  25683.              GpiSetCurrentPosition(hps, pptl);
  25684.              GpiFullArc(hps, flCmd, 0x10000L);
  25685.          }
  25686.          break;
  25687.      }
  25688.  
  25689.  
  25690.      if (global.fDisplayCrossHairs)
  25691.      {
  25692.          /* draw cross in center of pel */
  25693.  
  25694.          ptl.x = pptl->x - global.cxHalfFatPel;
  25695.          ptl.y = pptl->y;
  25696.          GpiSetCurrentPosition(hps, &ptl);
  25697.          ptl.x = pptl->x + global.cxHalfFatPel;
  25698.          GpiPolyLine(hps, 1L, &ptl);
  25699.  
  25700.          ptl.x = pptl->x;
  25701.          ptl.y = pptl->y - global.cyHalfFatPel;
  25702.          GpiSetCurrentPosition(hps, &ptl);
  25703.          ptl.y = pptl->y + global.cyHalfFatPel;
  25704.          GpiPolyLine(hps, 1L, &ptl);
  25705.      }
  25706.  }
  25707.  
  25708.  
  25709.  
  25710.  
  25711.  /************************************************************************
  25712.  *
  25713.  *   RoundControlPoints
  25714.  *
  25715.  ************************************************************************/
  25716.  
  25717.  VOID
  25718.  RoundControlPoints(hps, cptl, pptl1, pptl2, cx, cy)
  25719.  HPS hps;
  25720.  LONG cptl;
  25721.  PPOINTL pptl1;
  25722.  PPOINTL pptl2;
  25723.  LONG cx;
  25724.  LONG cy;
  25725.  {
  25726.      LONG cx2, cy2;
  25727.      LONG i;
  25728.      MATRIXLF matlf;
  25729.  
  25730.  
  25731.      /* copy the input buffer to the output/scratch buffer */
  25732.      for (i = 0; i < cptl; ++i)
  25733.          pptl2[i] = pptl1[i];
  25734.  
  25735.  
  25736.      /* set the transform, transform the points to device space (i.e. to
  25737.       * hpsFat dimensions), then restore the original transform
  25738.       */
  25739.      GpiQueryModelTransformMatrix(hps, 9L, &matlf);
  25740.      GpiSetModelTransformMatrix(hps, 9L, &global.matlf, TRANSFORM_REPLACE);
  25741.      GpiConvert(hps, CVTC_WORLD, CVTC_DEVICE, cptl, pptl2);
  25742.      GpiSetModelTransformMatrix(hps, 9L, &matlf, TRANSFORM_REPLACE);
  25743.  
  25744.  
  25745.      /* position each point in the center of its fatpel */
  25746.  
  25747.      cx2 = cx / 2L;
  25748.      cy2 = cy / 2L;
  25749.  
  25750.      for (i = 0; i < cptl; ++i, ++pptl2)
  25751.      {
  25752.          pptl2->x = pptl2->x * cx + cx2;
  25753.          pptl2->y = pptl2->y * cy + cy2;
  25754.      }
  25755.  }
  25756.  
  25757.  
  25758.  
  25759.  
  25760.  /************************************************************************
  25761.  *
  25762.  *   ComputeTransform
  25763.  *
  25764.  ************************************************************************/
  25765.  
  25766.  VOID
  25767.  ComputeTransform(prcl1, prcl2)
  25768.  PRECTL prcl1;
  25769.  PRECTL prcl2;
  25770.  {
  25771.      LONG xExt1, yExt1;
  25772.      LONG xExt2, yExt2;
  25773.      FIXED xScale, yScale;
  25774.  
  25775.  
  25776.      xExt1 = prcl1->xRight - prcl1->xLeft;
  25777.      yExt1 = prcl1->yTop   - prcl1->yBottom;
  25778.      xExt2 = prcl2->xRight - prcl2->xLeft;
  25779.      yExt2 = prcl2->yTop   - prcl2->yBottom;
  25780.  
  25781.  
  25782.      /* If the rectangles are of exactly the same dimensions, then
  25783.       * set the unity transform.  If not, compute the x and y scale
  25784.       * factors.  Note that in world coordinates rectangles are
  25785.       * inclusive-inclusive, whereas in device coordinates they are
  25786.       * inclusive-exclusive.  The extents of the destination are
  25787.       * therefore one pel too large as computed, so we subtract one
  25788.       * in the scale factor computation.
  25789.       */
  25790.  
  25791.      if (xExt1 == xExt2)
  25792.          xScale = 0x10000L;
  25793.      else
  25794.          xScale = ((xExt2-1L) * 0x10000L) / xExt1;
  25795.  
  25796.      if (yExt1 == yExt2)
  25797.          yScale = 0x10000L;
  25798.      else
  25799.          yScale = ((yExt2-1L) * 0x10000L) / yExt1;
  25800.  
  25801.  
  25802.      /* store the transform matrix for easy access */
  25803.  
  25804.      global.matlf.fxM11 = xScale;
  25805.      global.matlf.fxM12 = 0L;
  25806.      global.matlf. lM13 = 0L;
  25807.      global.matlf.fxM21 = 0L;
  25808.      global.matlf.fxM22 = yScale;
  25809.      global.matlf. lM23 = 0L;
  25810.      global.matlf. lM31 = 0L;
  25811.      global.matlf. lM32 = 0L;
  25812.      global.matlf. lM33 = 1L;
  25813.  }
  25814.  
  25815.  
  25816.  
  25817.  
  25818.  /************************************************************************
  25819.  *
  25820.  *   DrawPrimitive
  25821.  *
  25822.  ************************************************************************/
  25823.  
  25824.  VOID
  25825.  DrawPrimitive(hps, cptl, pptl)
  25826.  HPS hps;
  25827.  LONG cptl;
  25828.  PPOINTL pptl;
  25829.  {
  25830.      switch (global.usCurPrim)
  25831.      {
  25832.      case IDM_NOPRIM:
  25833.          break;
  25834.  
  25835.      case IDM_POLYLINE:
  25836.          GpiSetCurrentPosition(hps, pptl);
  25837.          GpiPolyLine(hps, cptl-1L, pptl + 1);
  25838.          break;
  25839.  
  25840.      case IDM_POLYFILLET:
  25841.          if (cptl >= 3L)
  25842.          {
  25843.              GpiSetCurrentPosition(hps, pptl);
  25844.              GpiPolyFillet(hps, cptl-1L, pptl + 1);
  25845.          }
  25846.          break;
  25847.  
  25848.      case IDM_POLYSPLINE:
  25849.          if (cptl >= 4L)
  25850.          {
  25851.              LONG cptSlack;    /* # points in pptl not usable by PolySpline */
  25852.  
  25853.              cptSlack = ((cptl-1L) % 3) + 1;
  25854.              GpiSetCurrentPosition( hps, pptl );
  25855.              GpiPolySpline( hps, cptl-cptSlack, pptl+1 );
  25856.          }
  25857.          break;
  25858.  
  25859.      case IDM_POINTARC:
  25860.          if (cptl >= 3L)
  25861.          {
  25862.              GpiSetCurrentPosition( hps, pptl );
  25863.              GpiPointArc( hps, pptl+1 );
  25864.          }
  25865.          break;
  25866.      }
  25867.  }
  25868.  
  25869.  
  25870.  
  25871.  
  25872.  /************************************************************************
  25873.  *
  25874.  *   UpdateSurfaceDims
  25875.  *
  25876.  ************************************************************************/
  25877.  
  25878.  VOID
  25879.  UpdateSurfaceDims()
  25880.  {
  25881.      SIZEL size;
  25882.      BITMAPINFOHEADER bminfo;
  25883.      AREABUNDLE ab;
  25884.  
  25885.  
  25886.      WinQueryWindowRect(global.hwnd, &global.rcl);
  25887.  
  25888.      /* compute size of small surface */
  25889.      global.rclFat.xLeft   = 0L;
  25890.      global.rclFat.yBottom = 0L;
  25891.      global.rclFat.xRight  = global.rcl.xRight / global.cxFatPel;
  25892.      global.rclFat.yTop          = global.rcl.yTop   / global.cyFatPel;
  25893.  
  25894.      /* compute size of fatpel version of small surface */
  25895.      global.rcl.xLeft   = 0L;
  25896.      global.rcl.yBottom = 0L;
  25897.      global.rcl.xRight  = global.rclFat.xRight * global.cxFatPel;
  25898.      global.rcl.yTop    = global.rclFat.yTop   * global.cyFatPel;
  25899.  
  25900.      ComputeTransform(&global.rcl, &global.rclFat);
  25901.  
  25902.      if ((global.rclFat.xRight <= global.rclFatBM.xRight) &&
  25903.          (global.rclFat.yTop   <= global.rclFatBM.yTop))
  25904.          return;
  25905.  
  25906.  
  25907.  
  25908.      /* The new fatbits surface doesn't fit in the bitmap, so we
  25909.       * have to make a new one.        If we don't have a DC or PS, make
  25910.       * those before making the bitmap.        If we do have a bitmap,
  25911.       * delete it before making the new one.
  25912.       */
  25913.  
  25914.      global.rclFatBM = global.rclFat;
  25915.  
  25916.      if (global.hbmFat)
  25917.      {
  25918.          GpiSetBitmap(global.hpsFat, NULL);
  25919.          GpiDeleteBitmap(global.hbmFat);
  25920.          GpiSetBitmap(global.hpsFatShadow, NULL);
  25921.          GpiDeleteBitmap(global.hbmFatShadow);
  25922.      }
  25923.  
  25924.      if (!global.hdcFat)
  25925.      {
  25926.          global.hdcFat = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL)
  25927.          if (!global.hdcFat)
  25928.              goto usd_error;
  25929.  
  25930.          global.hdcFatShadow = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL,
  25931.          if (!global.hdcFatShadow)
  25932.              goto usd_error;
  25933.      }
  25934.  
  25935.      if (!global.hpsFat)
  25936.      {
  25937.          size.cx = 0L;
  25938.          size.cy = 0L;
  25939.          global.hpsFat = GpiCreatePS(global.hab, global.hdcFat, &size,
  25940.                                   PU_PELS|GPIT_MICRO|GPIA_ASSOC);
  25941.          if (!global.hpsFat)
  25942.              goto usd_error;
  25943.  
  25944.          global.hpsFatShadow = GpiCreatePS(global.hab, global.hdcFatShadow, &s
  25945.                                   PU_PELS|GPIT_MICRO|GPIA_ASSOC);
  25946.          if (!global.hpsFatShadow)
  25947.              goto usd_error;
  25948.      }
  25949.  
  25950.      /* create bitmap with maximum color resolution (24-bit color) */
  25951.      bminfo.cbFix = sizeof(BITMAPINFOHEADER);
  25952.      bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
  25953.      bminfo.cy = (USHORT) (global.rclFatBM.yTop         - global.rclFatBM.yBot
  25954.      bminfo.cPlanes   = 1L;
  25955.      bminfo.cBitCount = 24L;
  25956.      global.hbmFat = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L);
  25957.      if (!global.hbmFat)
  25958.          goto usd_error;
  25959.      GpiSetBitmap(global.hpsFat, global.hbmFat);
  25960.  
  25961.      /* create a shadow bitmap of the one we just created */
  25962.      bminfo.cbFix = sizeof(BITMAPINFOHEADER);
  25963.      bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
  25964.      bminfo.cy = (USHORT) (global.rclFatBM.yTop         - global.rclFatBM.yBot
  25965.      bminfo.cPlanes   = 1L;
  25966.      bminfo.cBitCount = 24L;
  25967.      global.hbmFatShadow = GpiCreateBitmap(global.hpsFatShadow, &bminfo, 0L, 0
  25968.      if (!global.hbmFat)
  25969.          goto usd_error;
  25970.      GpiSetBitmap(global.hpsFatShadow, global.hbmFatShadow);
  25971.  
  25972.      /* clear bitmap surface to field color */
  25973.      ab.lColor = global.clrField;
  25974.      GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
  25975.      GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY,
  25976.  
  25977.      return;
  25978.  
  25979.  
  25980.  /* error exit point */
  25981.  
  25982.  usd_error:
  25983.      if (global.hpsFat)
  25984.          GpiDestroyPS(global.hpsFat);
  25985.      if (global.hpsFatShadow)
  25986.          GpiDestroyPS(global.hpsFatShadow);
  25987.      if (global.hdcFat)
  25988.          DevCloseDC(global.hdcFat);
  25989.      if (global.hdcFatShadow)
  25990.          DevCloseDC(global.hdcFatShadow);
  25991.  
  25992.      global.hpsFat        = NULL;
  25993.      global.hdcFat        = NULL;
  25994.      global.hpsFatShadow = NULL;
  25995.      global.hdcFatShadow = NULL;
  25996.  }
  25997.  
  25998.  
  25999.  
  26000.  
  26001.  /************************************************************************
  26002.  *
  26003.  *   AboutDlg
  26004.  *
  26005.  *   Process messages for the About box.
  26006.  *
  26007.  ************************************************************************/
  26008.  
  26009.  ULONG CALLBACK
  26010.  AboutDlg(hwnd, usMsg, mp1, mp2)
  26011.  HWND   hwnd;
  26012.  USHORT usMsg;
  26013.  MPARAM mp1;
  26014.  MPARAM mp2;
  26015.  {
  26016.      switch (usMsg)
  26017.      {
  26018.      case WM_COMMAND:
  26019.          if (SHORT1FROMMP(mp1) == DID_OK)
  26020.              WinDismissDlg(hwnd, TRUE);
  26021.          else
  26022.              return FALSE;
  26023.          break;
  26024.  
  26025.      default:
  26026.          return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  26027.      }
  26028.      return FALSE;
  26029.  }
  26030.  
  26031.  
  26032.  
  26033.  
  26034.  /************************************************************************
  26035.  *
  26036.  *   PelSizeDlg
  26037.  *
  26038.  *   Process messages for the Pel Size dialog box.
  26039.  *
  26040.  ************************************************************************/
  26041.  
  26042.  ULONG CALLBACK
  26043.  PelSizeDlg(hwnd, usMsg, mp1, mp2)
  26044.  HWND   hwnd;
  26045.  USHORT usMsg;
  26046.  MPARAM mp1;
  26047.  MPARAM mp2;
  26048.  {
  26049.      BOOL fRet = FALSE;
  26050.  
  26051.      switch (usMsg)
  26052.      {
  26053.      case WM_INITDLG:
  26054.          MySetWindowLong(hwnd, IDD_PELWIDTH,  global.cxFatPel);
  26055.          MySetWindowLong(hwnd, IDD_PELHEIGHT, global.cyFatPel);
  26056.          WinSendDlgItemMsg(hwnd, global.usPelShape,
  26057.                            BM_SETCHECK, (MPARAM)TRUE, 0L);
  26058.          return FALSE;
  26059.          break;
  26060.  
  26061.      case WM_COMMAND:
  26062.          switch (SHORT1FROMMP(mp1))
  26063.          {
  26064.          case IDD_OK:
  26065.              global.cxFatPel = MyGetWindowLong(hwnd, IDD_PELWIDTH);
  26066.              global.cyFatPel = MyGetWindowLong(hwnd, IDD_PELHEIGHT);
  26067.  
  26068.              if (global.cxFatPel < 1L)
  26069.                  global.cxFatPel = 1L;
  26070.  
  26071.              if (global.cyFatPel < 1L)
  26072.                  global.cyFatPel = 1L;
  26073.  
  26074.              global.cxHalfFatPel = global.cxFatPel / 2L;
  26075.              global.cyHalfFatPel = global.cyFatPel / 2L;
  26076.  
  26077.              global.usPelShape = SHORT1FROMMR( WinSendDlgItemMsg(hwnd, IDD_SQU
  26078.                                     BM_QUERYCHECKINDEX, 0L, 0L) + IDD_SQUARE);
  26079.  
  26080.  
  26081.              UpdateSurfaceDims();
  26082.  
  26083.              fRet = TRUE;
  26084.  
  26085.              /* fall through to some common code */
  26086.  
  26087.          case IDD_CANCEL:
  26088.              WinDismissDlg(hwnd, fRet);
  26089.              break;
  26090.  
  26091.          default:
  26092.              return FALSE;
  26093.          }
  26094.          break;
  26095.  
  26096.      default:
  26097.          return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  26098.      }
  26099.      return FALSE;
  26100.  }
  26101.  
  26102.  
  26103.  
  26104.  
  26105.  /************************************************************************
  26106.  *
  26107.  *   ColorsDlg
  26108.  *
  26109.  *   Process messages for the Set Colors dialog box.
  26110.  *
  26111.  ************************************************************************/
  26112.  
  26113.  ULONG CALLBACK
  26114.  ColorsDlg(hwnd, usMsg, mp1, mp2)
  26115.  HWND   hwnd;
  26116.  USHORT usMsg;
  26117.  MPARAM mp1;
  26118.  MPARAM mp2;
  26119.  {
  26120.      BOOL fRet = FALSE;
  26121.      BOOL fRGB;
  26122.      COLOR clrMathObj;
  26123.      COLOR clrRenderedObj;
  26124.      COLOR clrField;
  26125.      COLOR clrCrossHair;
  26126.      COLOR clrInterstice;
  26127.      COLOR clrControlPoints;
  26128.  
  26129.      switch (usMsg)
  26130.      {
  26131.      case WM_INITDLG:
  26132.          if (global.fRGB)
  26133.          {
  26134.              MySetWindowLongHex(hwnd, IDD_MATHOBJ,     global.clrMathObj);
  26135.              MySetWindowLongHex(hwnd, IDD_RENDEREDOBJ, global.clrRenderedObj);
  26136.              MySetWindowLongHex(hwnd, IDD_FIELD,             global.clrField);
  26137.              MySetWindowLongHex(hwnd, IDD_CROSSHAIRS,  global.clrCrossHair);
  26138.              MySetWindowLongHex(hwnd, IDD_INTERSTICE,  global.clrInterstice);
  26139.              MySetWindowLongHex(hwnd, IDD_CTLPOINTS,   global.clrControlPoints
  26140.          }
  26141.          else
  26142.          {
  26143.              MySetWindowLong   (hwnd, IDD_MATHOBJ,     global.clrMathObj);
  26144.              MySetWindowLong   (hwnd, IDD_RENDEREDOBJ, global.clrRenderedObj);
  26145.              MySetWindowLong   (hwnd, IDD_FIELD,             global.clrField);
  26146.              MySetWindowLong   (hwnd, IDD_CROSSHAIRS,  global.clrCrossHair);
  26147.              MySetWindowLong   (hwnd, IDD_INTERSTICE,  global.clrInterstice);
  26148.              MySetWindowLong   (hwnd, IDD_CTLPOINTS,   global.clrControlPoints
  26149.          }
  26150.          WinSendDlgItemMsg(hwnd, IDD_RGB, BM_SETCHECK, MPFROM2SHORT(global.fRG
  26151.          return FALSE;
  26152.          break;
  26153.  
  26154.      case WM_CONTROL:
  26155.          if ((SHORT1FROMMP(mp1) == IDD_RGB) && (SHORT2FROMMP(mp1)== BN_CLICKED
  26156.          {
  26157.              fRGB = !SHORT1FROMMR(WinSendDlgItemMsg(hwnd, IDD_RGB, BM_QUERYCHE
  26158.              WinSendDlgItemMsg(hwnd, IDD_RGB, BM_SETCHECK, MPFROM2SHORT(fRGB,0
  26159.  
  26160.              clrMathObj             = MyGetWindowLong(hwnd, IDD_MATHOBJ);
  26161.              clrRenderedObj   = MyGetWindowLong(hwnd, IDD_RENDEREDOBJ);
  26162.              clrField             = MyGetWindowLong(hwnd, IDD_FIELD);
  26163.              clrCrossHair     = MyGetWindowLong(hwnd, IDD_CROSSHAIRS);
  26164.              clrInterstice    = MyGetWindowLong(hwnd, IDD_INTERSTICE);
  26165.              clrControlPoints = MyGetWindowLong(hwnd, IDD_CTLPOINTS);
  26166.  
  26167.              if (fRGB)
  26168.              {
  26169.                  HPS hps;
  26170.  
  26171.                  /* for each color, get rgb value from index */
  26172.  
  26173.                  hps = WinGetPS(hwnd);
  26174.  
  26175.                  clrMathObj         = GpiQueryRGBColor(hps, 0L, clrMathObj);
  26176.                  clrRenderedObj         = GpiQueryRGBColor(hps, 0L, clrRendere
  26177.                  clrField         = GpiQueryRGBColor(hps, 0L, clrField);
  26178.                  clrCrossHair         = GpiQueryRGBColor(hps, 0L, clrCrossHair
  26179.                  clrInterstice         = GpiQueryRGBColor(hps, 0L, clrIntersti
  26180.                  clrControlPoints = GpiQueryRGBColor(hps, 0L, clrControlPoints
  26181.  
  26182.                  WinReleasePS(hps);
  26183.  
  26184.                  MySetWindowLongHex(hwnd, IDD_MATHOBJ,         clrMathObj);
  26185.                  MySetWindowLongHex(hwnd, IDD_RENDEREDOBJ, clrRenderedObj);
  26186.                  MySetWindowLongHex(hwnd, IDD_FIELD,         clrField);
  26187.                  MySetWindowLongHex(hwnd, IDD_CROSSHAIRS,  clrCrossHair);
  26188.                  MySetWindowLongHex(hwnd, IDD_INTERSTICE,  clrInterstice);
  26189.                  MySetWindowLongHex(hwnd, IDD_CTLPOINTS,         clrControlPoi
  26190.              }
  26191.              else
  26192.              {
  26193.                  HPS hps;
  26194.  
  26195.                  /* for each color, get nearest index value from rgb */
  26196.  
  26197.                  hps = WinGetPS(hwnd);
  26198.  
  26199.                  clrMathObj         = GpiQueryColorIndex(hps, 0L, clrMathObj);
  26200.                  clrRenderedObj         = GpiQueryColorIndex(hps, 0L, clrRende
  26201.                  clrField         = GpiQueryColorIndex(hps, 0L, clrField);
  26202.                  clrCrossHair         = GpiQueryColorIndex(hps, 0L, clrCrossHa
  26203.                  clrInterstice         = GpiQueryColorIndex(hps, 0L, clrInters
  26204.                  clrControlPoints = GpiQueryColorIndex(hps, 0L, clrControlPoin
  26205.  
  26206.                  WinReleasePS(hps);
  26207.  
  26208.                  MySetWindowLong   (hwnd, IDD_MATHOBJ,         clrMathObj);
  26209.                  MySetWindowLong   (hwnd, IDD_RENDEREDOBJ, clrRenderedObj);
  26210.                  MySetWindowLong   (hwnd, IDD_FIELD,         clrField);
  26211.                  MySetWindowLong   (hwnd, IDD_CROSSHAIRS,  clrCrossHair);
  26212.                  MySetWindowLong   (hwnd, IDD_INTERSTICE,  clrInterstice);
  26213.                  MySetWindowLong   (hwnd, IDD_CTLPOINTS,         clrControlPoi
  26214.              }
  26215.          }
  26216.          return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  26217.          break;
  26218.  
  26219.      case WM_COMMAND:
  26220.          switch (SHORT1FROMMP(mp1))
  26221.          {
  26222.          case IDD_OK:
  26223.              global.clrMathObj            = MyGetWindowLong(hwnd, IDD_MATHOBJ)
  26224.              global.clrRenderedObj   = MyGetWindowLong(hwnd, IDD_RENDEREDOBJ);
  26225.              global.clrField            = MyGetWindowLong(hwnd, IDD_FIELD);
  26226.              global.clrCrossHair     = MyGetWindowLong(hwnd, IDD_CROSSHAIRS);
  26227.              global.clrInterstice    = MyGetWindowLong(hwnd, IDD_INTERSTICE);
  26228.              global.clrControlPoints = MyGetWindowLong(hwnd, IDD_CTLPOINTS);
  26229.  
  26230.              global.fRGB = SHORT1FROMMR(WinSendDlgItemMsg(hwnd, IDD_RGB, BM_QU
  26231.  
  26232.              fRet = TRUE;
  26233.  
  26234.              /* fall through to some common code */
  26235.  
  26236.          case IDD_CANCEL:
  26237.              WinDismissDlg(hwnd, fRet);
  26238.              break;
  26239.  
  26240.          default:
  26241.              return FALSE;
  26242.          }
  26243.          break;
  26244.  
  26245.      default:
  26246.          return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
  26247.      }
  26248.      return FALSE;
  26249.  }
  26250.  
  26251.  
  26252.  
  26253.  
  26254.  /************************************************************************
  26255.  *
  26256.  *   MySetWindowLong
  26257.  *
  26258.  *   Sets the given control id to the value specified.
  26259.  *
  26260.  ************************************************************************/
  26261.  
  26262.  VOID
  26263.  MySetWindowLong(hWnd, id, num)
  26264.  HWND hWnd;
  26265.  USHORT id;
  26266.  LONG num;
  26267.  {
  26268.      char szStr[CCHSTR];
  26269.  
  26270.      sprintf((NPCH)szStr, "%ld", num);
  26271.      WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
  26272.  }
  26273.  
  26274.  
  26275.  
  26276.  
  26277.  /************************************************************************
  26278.  *
  26279.  *   MySetWindowLongHex
  26280.  *
  26281.  *   Sets the given control id to the value specified, in hexadecimal
  26282.  *   notation.
  26283.  *
  26284.  ************************************************************************/
  26285.  
  26286.  VOID
  26287.  MySetWindowLongHex(hWnd, id, num)
  26288.  HWND hWnd;
  26289.  USHORT id;
  26290.  LONG num;
  26291.  {
  26292.      char szStr[CCHSTR];
  26293.  
  26294.      sprintf((NPCH)szStr, "0x%06lX", num);
  26295.      WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
  26296.  }
  26297.  
  26298.  
  26299.  
  26300.  
  26301.  /************************************************************************
  26302.  *
  26303.  *   MyGetWindowLong
  26304.  *
  26305.  *   Returns the value from the given control id.
  26306.  *
  26307.  ************************************************************************/
  26308.  
  26309.  LONG
  26310.  MyGetWindowLong(hWnd, id)
  26311.  HWND hWnd;
  26312.  USHORT id;
  26313.  {
  26314.      char szStr[CCHSTR];
  26315.      LONG num;
  26316.  
  26317.      WinQueryWindowText(WinWindowFromID(hWnd, id), CCHSTR, (PCH)szStr);
  26318.  
  26319.      if (strchr(szStr, 'x'))
  26320.          sscanf((NPCH)szStr, "0x%lx", &num);
  26321.      else if (strchr(szStr, 'X'))
  26322.          sscanf((NPCH)szStr, "0X%lx", &num);
  26323.      else
  26324.          sscanf((NPCH)szStr, "%ld", &num);
  26325.  
  26326.      return num;
  26327.  }
  26328.  
  26329.  
  26330.  
  26331.  
  26332.  /************************************************************************
  26333.  *
  26334.  *   SaveWindowToFile
  26335.  *
  26336.  *   Copy the bits from the client rectangle (actually, just the fatpel
  26337.  *   area) into a bitmap, then save that bitmap.
  26338.  *
  26339.  ************************************************************************/
  26340.  
  26341.  VOID
  26342.  SaveWindowToFile(hwnd)
  26343.  HWND hwnd;
  26344.  {
  26345.      BITMAPINFOHEADER bminfo;
  26346.      HBITMAP hbm;
  26347.      HPS hps;
  26348.      POINTL aptl[3];
  26349.  
  26350.      /* create bitmap in display's favorite format */
  26351.      bminfo.cbFix = sizeof(BITMAPINFOHEADER);
  26352.      bminfo.cx = (USHORT) (global.rcl.xRight - global.rcl.xLeft);
  26353.      bminfo.cy = (USHORT) (global.rcl.yTop   - global.rcl.yBottom);
  26354.      bminfo.cPlanes   = 0L;
  26355.      bminfo.cBitCount = 0L;
  26356.      if (hbm = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L))
  26357.      {
  26358.          /* select it into the small bitmap's PS */
  26359.          GpiSetBitmap(global.hpsFat, hbm);
  26360.  
  26361.          /* GpiBitBlt from the window to the bitmap */
  26362.          hps = WinGetPS(hwnd);
  26363.  
  26364.          *((PRECTL)&aptl[0]) = global.rcl;
  26365.          aptl[2].x = 0L;
  26366.          aptl[2].y = 0L;
  26367.          GpiBitBlt(global.hpsFat, hps, 3L, aptl, ROP_SRCCOPY, 0L);
  26368.  
  26369.          WinReleasePS(hps);
  26370.  
  26371.          /* save the bitmap */
  26372.          WriteFile(hwnd, global.hpsFat);
  26373.      }
  26374.  
  26375.      /* deselect the bitmap and delete it */
  26376.      GpiSetBitmap(global.hpsFat, global.hbmFat);
  26377.      if (hbm)
  26378.          GpiDeleteBitmap(hbm);
  26379.  }
  26380.  
  26381.  
  26382.  
  26383.  
  26384.  /************************************************************************
  26385.  *
  26386.  *   WriteFile
  26387.  *
  26388.  *   Calls the OpenDlg's DlgFile function to ask the user what file name to
  26389.  *   save under.
  26390.  *
  26391.  ************************************************************************/
  26392.  
  26393.  VOID
  26394.  WriteFile(hwnd, hps)
  26395.  HWND hwnd;
  26396.  HPS hps;
  26397.  {
  26398.      HFILE hfile;
  26399.      DLF dlf;
  26400.      BITMAPINFOHEADER bmih;
  26401.  
  26402.      dlf.rgbAction        = DLG_SAVEDLG;
  26403.      dlf.rgbFlags        = 0;
  26404.      dlf.phFile                = &hfile;
  26405.      dlf.pszExt                = "";
  26406.      dlf.pszAppName        = "FatPel";
  26407.      dlf.pszInstructions = NULL;
  26408.      dlf.szFileName[0]        = '\0';
  26409.      dlf.szOpenFile[0]        = '\0';
  26410.      dlf.pszTitle        = "Save Bitmap";
  26411.  
  26412.  
  26413.      switch (DlgFile(hwnd,&dlf))
  26414.      {
  26415.      case TDF_ERRMEM:
  26416.      case TDF_INVALID:
  26417.          MyMessageBox(hwnd, "Error opening file.");
  26418.          break;
  26419.  
  26420.      case TDF_NOSAVE:
  26421.          break;
  26422.  
  26423.      default:
  26424.          bmih.cbFix     = sizeof(BITMAPINFOHEADER);
  26425.          bmih.cx        = (USHORT) global.rcl.xRight;
  26426.          bmih.cy        = (USHORT) global.rcl.yTop;
  26427.          bmih.cPlanes   = 0L;
  26428.          bmih.cBitCount = 0L;
  26429.  
  26430.          if (!WriteBMP(hfile, hps, &bmih))
  26431.              MyMessageBox(hwnd, "Error writing file.");
  26432.      }
  26433.  }
  26434.  
  26435.  
  26436.  
  26437.  
  26438.  /************************************************************************
  26439.  *
  26440.  *   WriteBMP
  26441.  *
  26442.  *   Write the bitmap out to a BMP format file.        Write the file
  26443.  *   header first, then the bitmap bits.  Space for the header
  26444.  *   and the bits is allocated.        Huge bitmaps are supported.
  26445.  *   Free up memory and close the file before leaving.  The file
  26446.  *   will have been opened by the time this function is called,
  26447.  *   and the file handle will be in the *pdlf structure.
  26448.  *
  26449.  ************************************************************************/
  26450.  
  26451.  BOOL
  26452.  WriteBMP(hfile, hps, pbmih)
  26453.  HFILE hfile;
  26454.  HPS hps;                 /* hps from which to get bitmap bits.           */
  26455.  PBITMAPINFOHEADER pbmih; /* Bitmap information.                    */
  26456.  {
  26457.      ULONG cScans;
  26458.      ULONG ulSize;         /* Number of bytes occupied by bitmap bits.
  26459.      USHORT cSegs;         /* Number of 64K segments in ulSize.
  26460.      USHORT cbExtra;         /* Bytes in last segment of ulSize.
  26461.      SEL selBits;         /* Base selector to bitmap bits.
  26462.      USHORT hugeshift;         /* Segment index shift value.
  26463.      USHORT cbBMHdr;         /* Size of bitmap header.
  26464.      PBITMAPFILEHEADER pbfh; /* Pointer to private copy of bitmap info data.
  26465.      USHORT cbWrite1;         /* Number of bytes to write first call to DosWri
  26466.      USHORT cbWrite2;         /* Number of bytes to write second call to DosWr
  26467.      USHORT cbWritten;         /* Number of bytes written by DosWrite.
  26468.      BOOL fRet = FALSE;         /* Function return code.
  26469.      int i;                 /* Generic loop index.
  26470.      struct
  26471.      {
  26472.          LONG cPlanes;
  26473.          LONG cBitCount;
  26474.      } bmFmt;
  26475.  
  26476.  
  26477.      /*******************************************************************
  26478.      * If the bitmap was created with either 0 planes or 0 bits per
  26479.      * pixel, then query the format to write with.  By asking for just
  26480.      * one format (two LONGs, or one instance of structure of bmFmt),
  26481.      * we'll get the device's favored format.
  26482.      *******************************************************************/
  26483.  
  26484.      if ((pbmih->cPlanes == 0) || (pbmih->cBitCount == 0))
  26485.      {
  26486.          if (!GpiQueryDeviceBitmapFormats(hps, 2L, (PLONG)&bmFmt))
  26487.              goto lfwrite_error_close_file;
  26488.      }
  26489.      else
  26490.      {
  26491.          bmFmt.cPlanes        = pbmih->cPlanes;
  26492.          bmFmt.cBitCount = pbmih->cBitCount;
  26493.      }
  26494.  
  26495.  
  26496.      /*******************************************************************
  26497.      * Determine size of bitmap header.        The header consists of a
  26498.      * a fixed-size part and a variable-length color table.  The
  26499.      * latter has  2^cBitCount  entries, each of which is sizeof(RGB)
  26500.      * bytes long.  The exception is when cBitCount is 24, in which
  26501.      * case the color table is omitted because the pixels are direct
  26502.      * rgb values.
  26503.      *******************************************************************/
  26504.  
  26505.      i = (int) bmFmt.cBitCount;
  26506.      if (i == 24)
  26507.          cbBMHdr = 0;
  26508.      else
  26509.          for (cbBMHdr = sizeof(RGB); i > 0; --i)
  26510.              cbBMHdr *= 2;
  26511.      cbBMHdr += sizeof(BITMAPFILEHEADER);
  26512.  
  26513.  
  26514.      /*******************************************************************
  26515.      * Copy structure from input to work buffer.  The call to
  26516.      * GpiQueryBitmapBits will have write-access to this, so we won't
  26517.      * let it have the user's data.
  26518.      *******************************************************************/
  26519.  
  26520.      pbfh = 0;
  26521.      if (DosAllocSeg(cbBMHdr, ((PUSHORT)&pbfh)+1, 0))
  26522.          goto lfwrite_error_close_file;
  26523.      pbfh->bmp = *pbmih;
  26524.      if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
  26525.      {
  26526.          pbfh->bmp.cPlanes   = (USHORT) bmFmt.cPlanes;
  26527.          pbfh->bmp.cBitCount = (USHORT) bmFmt.cBitCount;
  26528.      }
  26529.  
  26530.  
  26531.      /*******************************************************************
  26532.      * Allocate space for the bitmap bits -- all of them at once.
  26533.      * The extra ULONG casts are there to force all the arithmetic
  26534.      * to be done in 32 bits.
  26535.      *******************************************************************/
  26536.  
  26537.      ulSize = (
  26538.                 (
  26539.                   (
  26540.                     (ULONG)pbfh->bmp.cBitCount
  26541.                     * (ULONG)pbfh->bmp.cx
  26542.                     + 31L
  26543.                   ) / 32L
  26544.                 ) * (ULONG)pbfh->bmp.cPlanes * 4L
  26545.               ) * (ULONG)pbfh->bmp.cy;
  26546.  
  26547.      cSegs   = (USHORT)(ulSize/0x10000L);
  26548.      cbExtra = (USHORT)(ulSize%0x10000L);
  26549.      if (DosAllocHuge(cSegs, cbExtra, (PSEL)&selBits, 0, 0))
  26550.          goto lfwrite_error_free_header;
  26551.      if (DosGetHugeShift(&hugeshift))
  26552.          goto lfwrite_error_free_bits;
  26553.  
  26554.  
  26555.      /*******************************************************************
  26556.      * Tell GPI to give us the bits. The function returns the number
  26557.      * of scan lines of the bitmap that were copied.  We want all of
  26558.      * them at once.
  26559.      *******************************************************************/
  26560.  
  26561.      cScans = GpiQueryBitmapBits( hps
  26562.                                 , 0L
  26563.                                 , (ULONG)pbfh->bmp.cy
  26564.                                 , (PBYTE)MAKEP(selBits, 0)
  26565.                                 , (PBITMAPINFO)&pbfh->bmp);
  26566.      if (cScans != pbfh->bmp.cy)  /* compare with original number of scans */
  26567.          goto lfwrite_error_free_bits;
  26568.  
  26569.  
  26570.      /*******************************************************************
  26571.      * Fill in the extra header fields and write the header out to
  26572.      * the file.
  26573.      *******************************************************************/
  26574.  
  26575.      pbfh->usType    = 0x4D42;                  /* 'MB' */
  26576.      pbfh->cbSize    = ulSize + cbBMHdr;
  26577.      pbfh->xHotspot  = pbfh->bmp.cx / 2;
  26578.      pbfh->yHotspot  = pbfh->bmp.cy / 2;
  26579.      pbfh->offBits   = cbBMHdr;
  26580.  
  26581.      if (DosWrite( hfile
  26582.                  , (PVOID)pbfh
  26583.                  , cbBMHdr
  26584.                  , &cbWritten))
  26585.          goto lfwrite_error_free_bits;
  26586.      if (cbWritten != cbBMHdr)
  26587.          goto lfwrite_error_free_bits;
  26588.  
  26589.  
  26590.      /*******************************************************************
  26591.      * Write the bits out to the file. The DosWrite function allows a
  26592.      * maximum of 64K-1 bytes written at a time.  We get around this
  26593.      * by writing two 32K chunks for each 64K segment, and writing the
  26594.      * last segment in one piece.
  26595.      *******************************************************************/
  26596.  
  26597.      for (i = 0; i <= (SHORT) cSegs; ++i)
  26598.      {
  26599.          if (i < (SHORT) cSegs)
  26600.          {
  26601.              /* This segment is 64K bytes long, so split it up. */
  26602.              cbWrite1 = 0x8000;
  26603.              cbWrite2 = 0x8000;
  26604.          }
  26605.          else
  26606.          {
  26607.              /* This segment is less than 64K bytes long, so write it all. */
  26608.              cbWrite1 = cbExtra;
  26609.              cbWrite2 = 0;
  26610.          }
  26611.  
  26612.          /* There's a possibility that cbExtra will be 0, so check
  26613.           * to avoid an unnecessary system call.
  26614.           */
  26615.          if (cbWrite1 > 0)
  26616.          {
  26617.              if (DosWrite( hfile
  26618.                          , (PVOID)MAKEP(selBits+(i<<hugeshift), 0)
  26619.                          , cbWrite1
  26620.                          , &cbWritten))
  26621.                  goto lfwrite_error_free_bits;
  26622.              if (cbWrite1 != cbWritten)
  26623.                  goto lfwrite_error_free_bits;
  26624.          }
  26625.  
  26626.          /* This will always be skipped on the last partial segment. */
  26627.          if (cbWrite2 > 0)
  26628.          {
  26629.              if (DosWrite( hfile
  26630.                          , (PVOID)MAKEP(selBits+(i<<hugeshift), cbWrite1)
  26631.                          , cbWrite2
  26632.                          , &cbWritten))
  26633.                  goto lfwrite_error_free_bits;
  26634.              if (cbWrite2 != cbWritten)
  26635.                  goto lfwrite_error_free_bits;
  26636.          }
  26637.      }
  26638.  
  26639.      fRet = TRUE;     /* The bits are on the disk. */
  26640.  
  26641.  
  26642.      /*******************************************************************
  26643.      * Close the file, free the buffer space and leave.        This is a
  26644.      * common exit point from the function.  Since the same cleanup
  26645.      * operations need to be performed for such a large number of
  26646.      * possible error conditions, this is concise way to do the right
  26647.      * thing.
  26648.      *******************************************************************/
  26649.  
  26650.  lfwrite_error_free_bits:
  26651.      DosFreeSeg(selBits);
  26652.  lfwrite_error_free_header:
  26653.      DosFreeSeg(*((PUSHORT)&pbfh+1));
  26654.  lfwrite_error_close_file:
  26655.      DosClose(hfile);
  26656.      return fRet;
  26657.  }
  26658.  
  26659.  
  26660.  
  26661.  
  26662.  /************************************************************************
  26663.  *
  26664.  *   MyMessageBox
  26665.  *
  26666.  *   Displays a message box with the given string.  To simplify matters,
  26667.  *   the box will always have the same title ("FatPel"), will always
  26668.  *   have a single button ("Ok"), will always have an exclamation point
  26669.  *   icon, and will always be application modal.
  26670.  *
  26671.  ************************************************************************/
  26672.  
  26673.  VOID
  26674.  MyMessageBox(hWnd, sz)
  26675.  HWND hWnd;
  26676.  PSZ sz;
  26677.  {
  26678.      static char *szTitle = "FatPel Application";
  26679.  
  26680.      WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, 0,
  26681.                    MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
  26682.  }
  26683.  
  26684.  
  26685.  FDIR.C
  26686.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\FDIR\FDIR.C
  26687.  
  26688.  /*************************************************************
  26689.  
  26690.   This sample code demonstrates conversion from longnames to 8.3 and how
  26691.   to determine the longname from the EA of a FAT file.
  26692.   Should be compiled with the Large model.
  26693.  
  26694.   Written by Jeff Johnson 6/20/89
  26695.  
  26696.   This code was written to demonstrate two new features of OS/2 V1.2:
  26697.   1) How to convert long filenames to the appropriate 8.3 names.
  26698.   2) How to find a file's longname on a FAT system by checking its EA.
  26699.  
  26700.   Procedures in this file:
  26701.     main()             Does the main directory program calling support modules
  26702.     Convert_to_8dot3() Converts a longname to 8.3 name
  26703.     ParsePathName()    Breaks a full path into its 3 components
  26704.     QueryLongname()    Gets the .LONGNAME EA for a given file
  26705.     QueryIFS()         Determines the IFS type of a drive
  26706.  
  26707.  **************************************************************/
  26708.  
  26709.  #define INCL_DOSFILEMGR
  26710.  #define INCL_BASE
  26711.  #include <os2.h>
  26712.  
  26713.  #include <string.h>
  26714.  #include <malloc.h>
  26715.  #include <stdio.h>
  26716.  
  26717.  #define FAT  0
  26718.  #define HPFS 1
  26719.  #define GetInfoLevel1 0x0001
  26720.  #define GetInfoLevel3 0x0003
  26721.  
  26722.  VOID Convert_to_8dot3(CHAR *,CHAR *);
  26723.  VOID ParsePathName(CHAR *,CHAR *,CHAR *,CHAR *);
  26724.  VOID QueryLongname(CHAR *,CHAR *);
  26725.  VOID QueryIFS(CHAR *,PUSHORT,PUSHORT);
  26726.  
  26727.  
  26728.  /*
  26729.   * Function name: main()
  26730.   *
  26731.   * Parameters:  argc, argv.  If the user places a file spec on the command
  26732.   *              line it is used to select/filter the directory listing.
  26733.   *              Otherwise, the default directory is listed.
  26734.   *
  26735.   * Returns: Always exits with 0.
  26736.   *
  26737.   * Purpose: main() coordinates the directory process by calling the
  26738.   *          appropriate setup routines, then handling the DosFindNext
  26739.   *          loop for each file.
  26740.   *
  26741.   * Usage/Warnings:  Very little error checking is done as the code is written
  26742.   *                  to demonstrate longname conversion/EA reading, not as
  26743.   *                  a finished app.
  26744.   *
  26745.   * Calls: ParsePathName(), QueryIFS(), Convert_to_8dot3(), QueryLongname()
  26746.   */
  26747.  
  26748.  main (int argc, char *argv[])
  26749.  {
  26750.      USHORT uRetval,hdir=0xffff,SearchCount=1;
  26751.      PFILEFINDBUF pfbuf;
  26752.      char szDrive[3],szPath[260],szFilename[CCHMAXPATH],szFullPath[CCHMAXPATH]
  26753.      USHORT ifsloc,ifsname;
  26754.      char *szFilePtr,szLongName[260];
  26755.  
  26756.      if(argc<2)
  26757.          ParsePathName("",szDrive,szPath,szFilename);
  26758.      else
  26759.          ParsePathName(argv[1],szDrive,szPath,szFilename);
  26760.  
  26761.      if(strlen(szFilename) == 0)
  26762.          strcpy(szFilename,"*");
  26763.  
  26764.      strcpy(szFullPath,szDrive);
  26765.      strcat(szFullPath,szPath);
  26766.      szFilePtr = szFullPath + strlen(szFullPath);
  26767.      strcat(szFullPath,szFilename);
  26768.  
  26769.      QueryIFS(szDrive,&ifsloc,&ifsname);
  26770.  
  26771.      if(ifsname != FAT && ifsname != HPFS)
  26772.      {
  26773.          printf("Unrecognized file system.\n");
  26774.          return 0;
  26775.      }
  26776.  
  26777.      if(ifsname == FAT)
  26778.          printf("FAT -> HPFS directory listing\n");
  26779.      else
  26780.          printf("HPFS -> FAT directory listing\n");
  26781.  
  26782.  
  26783.      pfbuf = (PFILEFINDBUF) malloc(sizeof(FILEFINDBUF));
  26784.      uRetval=DosFindFirst(szFullPath,(PHDIR) &hdir,FILE_DIRECTORY,
  26785.                           pfbuf,sizeof(FILEFINDBUF),&SearchCount,0L);
  26786.  
  26787.      if(uRetval)
  26788.      {
  26789.          printf("No files found.\n");
  26790.          return 0;
  26791.      }
  26792.  
  26793.      do
  26794.      {
  26795.          if(ifsname == FAT)
  26796.          {
  26797.              strcpy(szFilePtr,pfbuf->achName);  /* Drop in name after path */
  26798.  
  26799.              QueryLongname(szFullPath,szLongName);
  26800.  
  26801.              if(strlen(szLongName) == 0)
  26802.                  printf("%s\n",pfbuf->achName);
  26803.              else
  26804.                  printf("%s\n",szLongName);
  26805.          }
  26806.          else   /* It's HPFS */
  26807.          {
  26808.              Convert_to_8dot3(pfbuf->achName,szFilename);
  26809.              printf("%s\n",szFilename);
  26810.          }
  26811.      } while(!(uRetval=DosFindNext(hdir,pfbuf,
  26812.                                    sizeof(FILEFINDBUF),&SearchCount)));
  26813.  }
  26814.  
  26815.  
  26816.  /*
  26817.   * Function name: Convert_to_8dot3()
  26818.   *
  26819.   * Parameters:  szLong points to the input long file name.
  26820.   *              szFat points to a return buffer for the FAT compatible name.
  26821.   *
  26822.   * Returns: VOID. The converted string is placed in szFat buffer.
  26823.   *
  26824.   * Purpose: Converts a HPFS longname to the standard 8.3 name.  This is
  26825.   *          done as follows:  The extension is the first 3 characters after
  26826.   *          the last dot, no extension if there are no dots.  The file stem
  26827.   *          is at most 8 character and is taken from the beginning of the
  26828.   *          longname string, replacing all dots with underscores.
  26829.   *
  26830.   * Usage/Warnings:  Should be bulletproof.  Exception code included to allow
  26831.   *                  the special file name '..' through.
  26832.   *
  26833.   * Calls:
  26834.   */
  26835.  
  26836.  VOID Convert_to_8dot3(CHAR *szLong,CHAR *szFat)
  26837.  {
  26838.      USHORT usStemMaxLen; /* Holds the max size the 8 char base can be */
  26839.      USHORT cnt;
  26840.      CHAR   szStem[9],szExt[4];  /* Holds the Stem and Extension */
  26841.      CHAR   *szLastDot;          /* Pointer to the last dot */
  26842.  
  26843.      if(!strcmp(szLong,"..")) /* Allow the predecessor file to pass thru */
  26844.      {
  26845.          strcpy(szFat,"..");
  26846.          return;
  26847.      }
  26848.  
  26849.      szLastDot = strrchr(szLong,'.'); /* Find the last period */
  26850.  
  26851.      if(szLastDot)  /* There is at least one period */
  26852.      {
  26853.          strncpy(szExt,szLastDot+1,3);       /* 1st 3 chars after . are ext */
  26854.          szExt[3]=0;
  26855.          usStemMaxLen = szLastDot - szLong;  /* Max stem is everything b4 . */
  26856.      }
  26857.      else
  26858.      {
  26859.          *szExt = 0;                         /* No extension */
  26860.          usStemMaxLen = strlen(szLong);      /* Stem can be whole string */
  26861.      }
  26862.  
  26863.      if(usStemMaxLen>8)                      /* Limit stem to 8 chars */
  26864.          usStemMaxLen = 8;
  26865.  
  26866.      for(cnt=0;cnt<usStemMaxLen;cnt++)       /* Copy in chars to form stem */
  26867.      {
  26868.          switch(szLong[cnt])
  26869.          {
  26870.              case '.':                       /* Convert .'s to _'s */
  26871.                  szStem[cnt] = '_';
  26872.                  break;
  26873.              default:                        /* Copy all other chars */
  26874.                  szStem[cnt] = szLong[cnt];
  26875.                  break;
  26876.          }
  26877.      }
  26878.      szStem[cnt] = 0;
  26879.  
  26880.      /* Put it all together */
  26881.      strcpy(szFat,szStem);
  26882.      strcat(szFat,".");
  26883.      strcat(szFat,szExt);
  26884.  }
  26885.  
  26886.  
  26887.  /*
  26888.   * Function name: ParsePathName()
  26889.   *
  26890.   * Parameters:  szFullPath points to the input full path name.
  26891.   *              szDrive points to the return buffer for the drive letter.
  26892.   *              szPath points to the return buffer for the path.
  26893.   *              szFilename points to the return buffer for the Filename.
  26894.   *
  26895.   * Returns: VOID. The converted string is placed in last 3 passed params.
  26896.   *
  26897.   * Purpose: Break a full path string and break it into its three components.
  26898.   *          If the passed string doesn't have a drive, the current letter is
  26899.   *          fetched an placed in the return buffer.  The same is true for
  26900.   *          the path buffer.
  26901.   *
  26902.   * Usage/Warnings:  Error checking should be done on the DOS calls.
  26903.   *
  26904.   * Calls:
  26905.   */
  26906.  
  26907.  VOID ParsePathName(CHAR *szFullPath,CHAR *szDrive,CHAR *szPath,CHAR *szFilena
  26908.  {
  26909.      CHAR *szBack;          /* Used to find last backslach */
  26910.      USHORT usPathLen;      /* Holds the length of the path part of string */
  26911.  
  26912.      *szPath = *szFilename = 0;
  26913.  
  26914.      /* Do the Drive letter */
  26915.      if(*(szFullPath+1)==':')           /* If there is a drive letter */
  26916.      {
  26917.          szDrive[0] = *szFullPath;
  26918.  
  26919.          szFullPath += 2;
  26920.      }
  26921.      else                               /* We take the default */
  26922.      {
  26923.          USHORT dno;  /* Drive number */
  26924.          ULONG  dmap; /* Map of available drives */
  26925.  
  26926.          DosQCurDisk((PUSHORT) &dno,(PULONG) &dmap);
  26927.          *szDrive = (CHAR)( dno + 'A'-1);
  26928.      }
  26929.      szDrive[1] = ':';          /* Add the colon */
  26930.      szDrive[2] = (CHAR) 0;
  26931.  
  26932.      /* Now do the path */
  26933.      szBack = strrchr(szFullPath,'\\');
  26934.      if(szBack)                         /* There is at least 1 backslash */
  26935.      {
  26936.         usPathLen = szBack - szFullPath + 1;
  26937.         strncpy(szPath,szFullPath,usPathLen);   /* Copy path */
  26938.         szPath[usPathLen] = (CHAR) 0;
  26939.      }
  26940.      else
  26941.      {
  26942.         *szPath = (CHAR) 0;
  26943.         szBack  = szFullPath-1;  /* Points 1 char before the file name */
  26944.      }
  26945.  
  26946.      /* Finally do the file name */
  26947.      strcpy(szFilename,szBack+1);
  26948.  }
  26949.  
  26950.  
  26951.  /*
  26952.   * Function name: QueryLongname()
  26953.   *
  26954.   * Parameters:  szfile points to the file to be queried.
  26955.   *              szLong points to the return buffer for the long filename.
  26956.   *
  26957.   * Returns: VOID. The converted string is placed in last 3 passed params.
  26958.   *
  26959.   * Purpose: Looks for an EA named .LONGNAME attached to szfile.  If found,
  26960.   *          it places the EA value in the return buffer.
  26961.   *
  26962.   * Usage/Warnings:  Routine assumes that the EA format is LP ASCII which
  26963.   *                  is what the specs required, but probably the exception
  26964.   *                  handling should be a bit tighter.  Return buf should be
  26965.   *                  at least CCHMAXPATH long to accomodate max length names.
  26966.   *                  Note also that no check is made to prevent overwriting
  26967.   *                  the end of the return buffer.
  26968.   *
  26969.   * Calls:
  26970.   */
  26971.  
  26972.  VOID QueryLongname(CHAR *szfile,CHAR *szLong)
  26973.  {
  26974.      CHAR    *szEAName;  /* Points to the .LONGNAME string */
  26975.      SHORT   cbEAName;   /* Length of the .LONGNAME string */
  26976.  
  26977.      SHORT   cbFEAList;  /* The length of the FEA buf to be used */
  26978.      SHORT   cbGEAList;  /* "                 GEA                */
  26979.  
  26980.      CHAR   cvFdump[300],cvGdump[50];     /* FEA and GEA buffers */
  26981.      FEALIST *pFEAList;                   /* Pointers to the buffers */
  26982.      GEALIST *pGEAList;
  26983.      EAOP    eaop;
  26984.                                           /* Pass struct for Dos call */
  26985.      USHORT  usRetval;
  26986.      SHORT   cbRet;
  26987.      CHAR    *szT;
  26988.  
  26989.      *szLong = (CHAR) 0;                /* Default if we can't get the EA */
  26990.  
  26991.      szEAName = ".LONGNAME";        /* The particular EA we are interested in
  26992.      cbEAName = strlen(szEAName);
  26993.  
  26994.      cbGEAList = sizeof(GEALIST) + cbEAName;  /* Set buf lengths */
  26995.      cbFEAList = sizeof(FEALIST) + cbEAName+1 + 256 + 2;
  26996.  
  26997.      pFEAList = (FEALIST *) cvFdump;   /* Set pointers to 2 buffers */
  26998.      pGEAList = (GEALIST *) cvGdump;
  26999.  
  27000.      eaop.fpGEAList = (PGEALIST) pGEAList; /* Build the EAOP struct */
  27001.      eaop.fpFEAList = (PFEALIST) pFEAList;
  27002.  
  27003.      pGEAList->cbList = cbGEAList;       /* Fill in GEA buf length */
  27004.      pGEAList->list[0].cbName = (CHAR) cbEAName; /* Set .longname length */
  27005.      strcpy((char *) pGEAList->list[0].szName, (char *) szEAName);
  27006.  
  27007.      pFEAList -> cbList = cbFEAList; /* Set length of receiving buffer */
  27008.  
  27009.      usRetval = DosQPathInfo(szfile,      /* Get the .LONGNAME EA */
  27010.                              GetInfoLevel3,
  27011.                              (PVOID) &eaop,
  27012.                              sizeof(EAOP),
  27013.                              0L);
  27014.  
  27015.      if(usRetval != 0) /* There was an error */
  27016.         return;
  27017.  
  27018.      if(pFEAList->list[0].cbValue <=0)  /* It couldn't return EA value */
  27019.         return;
  27020.  
  27021.      szT = (CHAR *) pFEAList + sizeof(FEALIST) + cbEAName + 1;
  27022.      if (*((USHORT *) szT) == 0xfffd) /* length preceeded ASCII */
  27023.      {
  27024.          szT += 2;
  27025.          cbRet = *((USHORT *) szT);
  27026.  
  27027.          szT += 2;
  27028.          strncpy(szLong,szT,cbRet);
  27029.          szLong[cbRet]=0;
  27030.      }
  27031.  }
  27032.  
  27033.  
  27034.  /*
  27035.   * Function name: QueryIFS()
  27036.   *
  27037.   * Parameters:  szDrive points to drive letter to be queried.
  27038.   *              pusLocale will contain the location of the drive:
  27039.   *                        3=local, 4=remote.
  27040.   *              pusFSDName will contain the IFS type: 0=FAT, 1=HPFS, 2=Other.
  27041.   *
  27042.   * Returns: VOID.  All returns are in the last 2 params.
  27043.   *
  27044.   * Purpose: Mainly used to determine whether the file system is FAT or HPFS.
  27045.   *          also returns info on whether the drive is local or remote.
  27046.   *
  27047.   * Usage/Warnings:  Error checking on the DOS call should be implemented.
  27048.   *                  The buffer filled by DosQFSAttach is structured as follow
  27049.   *                         USHORT iType;
  27050.   *                         USHORT cbName;
  27051.   *                         UCHAR  szName[];
  27052.   *                         USHORT cbFSDName;
  27053.   *                         UCHAR  szFSDName[];
  27054.   *                         ...
  27055.   *
  27056.   * Calls:
  27057.   */
  27058.  
  27059.  VOID QueryIFS(CHAR *szDrive,PUSHORT pusLocale,PUSHORT pusFSDName)
  27060.  {
  27061.      CHAR vChunk[100];             /* Buffer for data from DosQFSAttach */
  27062.      USHORT usChunkLen=100;
  27063.      USHORT usTemp;                /* Holds offset for FSDName */
  27064.  
  27065.      DosQFSAttach(szDrive,0,GetInfoLevel1, vChunk,&usChunkLen,0L);
  27066.  
  27067.      *pusLocale = *((PUSHORT) vChunk);  /* Set local from 1st USHORT *);*/
  27068.  
  27069.      /* Skip over iType, cbName, szName, and cbFSDName fields to szFSDName */
  27070.      usTemp = *((PUSHORT) &vChunk[sizeof(USHORT)]) + sizeof(USHORT)*3 + 1;
  27071.  
  27072.      if(!strcmp("FAT",&vChunk[usTemp]))
  27073.      {
  27074.          *pusFSDName = 0;
  27075.          return;
  27076.      }
  27077.      if(!strcmp("HPFS",&vChunk[usTemp]))
  27078.      {
  27079.          *pusFSDName = 1;
  27080.          return;
  27081.      }
  27082.  
  27083.      *pusFSDName = 2;
  27084.      return;
  27085.  }
  27086.  
  27087.  
  27088.  
  27089.  FILE.C
  27090.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\STOCK\FILE.C
  27091.  
  27092.  /***        file.C - standard file dialogs
  27093.   *
  27094.   */
  27095.  
  27096.  #define INCL_DOSERRORS
  27097.  #define INCL_WINCOMMON
  27098.  #define INCL_WINBUTTONS
  27099.  #define INCL_WINDIALOGS
  27100.  #define INCL_WINFRAMEMGR
  27101.  #define INCL_WININPUT
  27102.  #define INCL_WINLISTBOXES
  27103.  #define INCL_WINMENUS
  27104.  #define INCL_WINMESSAGEMGR
  27105.  
  27106.  #include <os2.h>
  27107.  #include <stddef.h>
  27108.  #include <stdlib.h>
  27109.  #include <stdio.h>
  27110.  #include <string.h>
  27111.  
  27112.  #include "fileid.h"
  27113.  #include "file.h"
  27114.  #include "mem.h"
  27115.  
  27116.  #define dbg(x)        x
  27117.  
  27118.  typedef struct {    /* fctl */
  27119.      char    *pszTitle;                        // Dialog box title
  27120.      char    *pszPattern;                // wild-card file pattern
  27121.      char    achPath[CCHMAXPATH];        // full path of file
  27122.  } FILECTL;
  27123.  typedef FILECTL *PFILECTL;
  27124.  
  27125.  MRESULT EXPENTRY FileDlgProc(HWND hwnd,USHORT msg,MPARAM mp1,MPARAM mp2);
  27126.  
  27127.  USHORT                beginSearch(char *psz, USHORT *pattr);
  27128.  BOOL                changeDir(HWND hwndDlg, PFILECTL pfctl);
  27129.  BOOL                changeDrive(HWND hwndDlg, PFILECTL pfctl);
  27130.  BOOL                changeFile(HWND hwndDlg, PFILECTL pfctl);
  27131.  void                endSearch(void);
  27132.  USHORT                nextSearch(char *psz, USHORT *pattr);
  27133.  USHORT                niceWinDlgBox(HWND hwndParent, HWND hwndOwner, PFNWP pf
  27134.                              HMODULE hmod, USHORT idDlg, PVOID pCreateParams);
  27135.  BOOL                setCurDir(HWND hwndDlg);
  27136.  BOOL                setDir(HWND hwndDlg);
  27137.  BOOL                setDrive(HWND hwndDlg);
  27138.  BOOL                setFile(HWND hwndDlg);
  27139.  char *                trimBlanks(char * psz);
  27140.  
  27141.  
  27142.  static BOOL        fDidOK;                        // true if OK was just pres
  27143.  
  27144.  static HDIR        hdir;                        // directory search handle
  27145.  
  27146.  static USHORT        itDrive;                // last item selected in Drive L
  27147.  static USHORT        itDir;                        // last item selected in D
  27148.  static USHORT        itFile;                        // last item selected in
  27149.  
  27150.  
  27151.  char *FileOpen(HWND hwndOwner,char *pszTitle,char *pszPattern)
  27152.  {
  27153.      BOOL    fOK;
  27154.      FILECTL fctl;
  27155.  
  27156.      fctl.pszTitle = pszTitle;
  27157.      fctl.pszPattern = pszPattern;
  27158.  
  27159.      fOK = niceWinDlgBox(HWND_DESKTOP, hwndOwner, FileDlgProc,
  27160.                              NULL, IDD_FILE, &fctl);
  27161.  
  27162.      if (fOK)
  27163.          return MemStrDup(fctl.achPath);
  27164.      else
  27165.          return NULL;
  27166.  }
  27167.  
  27168.  
  27169.  USHORT        niceWinDlgBox(HWND hwndParent, HWND hwndOwner, PFNWP pfnDlgProc
  27170.                              HMODULE hmod, USHORT idDlg, PVOID pCreateParams)
  27171.  {
  27172.      HAB            hab;
  27173.      HWND    hwndDlg;
  27174.      USHORT  us;
  27175.      SWP            swp;
  27176.      SWP            swpDesk;
  27177.  
  27178.      hwndDlg = WinLoadDlg(hwndParent, hwndOwner, pfnDlgProc,
  27179.                              hmod, idDlg, pCreateParams);
  27180.  
  27181.      WinQueryWindowPos(hwndDlg,&swp);  // get window position
  27182.      WinQueryWindowPos(HWND_DESKTOP,&swpDesk); // get desktop
  27183.  
  27184.      // center dialog box on screen
  27185.  
  27186.      swp.x = (swpDesk.cx - swp.cx) >> 1;
  27187.      swp.y = (swpDesk.cy - swp.cy) >> 1;
  27188.  
  27189.      hab = WinQueryAnchorBlock(hwndDlg);
  27190.      WinSetMultWindowPos(hab,&swp,1);
  27191.  
  27192.      us = WinProcessDlg(hwndDlg);
  27193.      WinDestroyWindow(hwndDlg);
  27194.  
  27195.      return us;
  27196.  }
  27197.  
  27198.  /***        FileDlgProc - "File" Dialog Procedure
  27199.  *
  27200.  */
  27201.  MRESULT EXPENTRY FileDlgProc(HWND hwnd,USHORT msg,MPARAM mp1,MPARAM mp2)
  27202.  {
  27203.      static char            ach[CCHMAXPATH];
  27204.             USHORT   attr;
  27205.      static HWND            hwndFocus;
  27206.      static HWND            hwndLBDir;
  27207.      static HWND            hwndLBDrive;
  27208.      static HWND            hwndLBFile;
  27209.      static HWND            hwndText;
  27210.      static USHORT   idLB;
  27211.      static USHORT   idLBPrevious;
  27212.             USHORT   it;
  27213.      static PFILECTL pfctl;
  27214.             USHORT   rc;
  27215.  
  27216.      switch (msg) {
  27217.  
  27218.      case WM_INITDLG:
  27219.          pfctl = (PFILECTL)(VOID *)SHORT1FROMMP(mp2);        // set file contr
  27220.  
  27221.          hwndLBDir   = WinWindowFromID(hwnd, IDL_DIR);
  27222.          hwndLBDrive = WinWindowFromID(hwnd, IDL_DRIVE);
  27223.          hwndLBFile  = WinWindowFromID(hwnd, IDL_FILE);
  27224.          hwndText = WinWindowFromID(hwnd, IDC_TEXT);
  27225.          idLBPrevious = 0;                // no previous focus
  27226.  
  27227.          WinSetWindowText(hwnd, pfctl->pszTitle);  // set dialog title
  27228.          WinSetWindowText(hwndText, pfctl->pszPattern);        // init file pa
  27229.  
  27230.          setDrive(hwnd);                        // init drive list box
  27231.          setDir(hwnd);                        // update dir list
  27232.          setFile(hwnd);                        // update file list
  27233.          setCurDir(hwnd);                // init current drive/dir string
  27234.  
  27235.          WinDefDlgProc(hwnd, msg, mp1, mp2); // do default stuff
  27236.  
  27237.          hwndFocus = hwndText;
  27238.          WinSetFocus(HWND_DESKTOP,hwndFocus);
  27239.          return (MRESULT) TRUE;
  27240.  
  27241.      case WM_COMMAND:
  27242.          switch (LOUSHORT(mp1)) {
  27243.  
  27244.          case DID_OK:                        // store updated list
  27245.              dbg( printf("WM_COMMAND: DID_OK\n") );
  27246.              WinQueryWindowText(hwndText, CCHMAXPATH, ach);
  27247.              trimBlanks(ach);        // Trim leading/trailing blanks
  27248.              WinSetWindowText(hwndText, ach);
  27249.              dbg( printf("   opening %s\n",ach) );
  27250.              rc = DosQFileMode(ach,&attr,0L); // Does file exist?
  27251.              dbg( printf("   DosQFileMode rc=%d\n",rc) );
  27252.  
  27253.              // If directory is specified, pretend file not found
  27254.  
  27255.              if (attr & FILE_DIRECTORY)
  27256.                  rc = ERROR_FILE_NOT_FOUND;
  27257.  
  27258.              fDidOK = TRUE;
  27259.              switch (rc) {
  27260.  
  27261.              case NO_ERROR: {
  27262.                  USHORT        cch=CCHMAXPATH;
  27263.  
  27264.                  rc = DosQPathInfo(
  27265.                      ach,                // Path specifiec
  27266.                      FIL_QUERYFULLNAME,        // Get fully-qualified name
  27267.                      pfctl->achPath,        // Return buffer
  27268.                      CCHMAXPATH,                // Return buffer size
  27269.                      0L                        // Reserved
  27270.                      );
  27271.                  if (rc == 0)
  27272.                      WinDismissDlg(hwnd,TRUE); // return SUCCESS
  27273.                  }
  27274.                  return FALSE;
  27275.  
  27276.              case ERROR_FILE_NOT_FOUND:
  27277.              case ERROR_PATH_NOT_FOUND:
  27278.                  // check for and process user wild-card pattern
  27279.                  if (strcmp(ach,pfctl->pszPattern) != 0)
  27280.                      setFile(hwnd);
  27281.                  break;                        // continue dialog
  27282.  
  27283.              case ERROR_ACCESS_DENIED:
  27284.              case ERROR_DRIVE_LOCKED:
  27285.              case ERROR_NOT_DOS_DISK:
  27286.                  WinMessageBox(HWND_DESKTOP, hwnd, "Access Denied",
  27287.                                "Error", NULL, MB_ICONEXCLAMATION);
  27288.                  break;
  27289.  
  27290.              default:
  27291.                  break;
  27292.              }
  27293.              WinSetFocus(HWND_DESKTOP,hwndFocus);
  27294.              break;
  27295.  
  27296.          case DID_CANCEL:
  27297.              WinDismissDlg(hwnd, NULL);
  27298.              break;
  27299.          }
  27300.          break;
  27301.  
  27302.      case WM_CONTROL:
  27303.          idLBPrevious = idLB;                // remember previous focus
  27304.          idLB = SHORT1FROMMP(mp1);
  27305.          dbg (printf("WM_CONTROL: id = %04x hwndLB=%08x\n",idLB,mp2) );
  27306.          switch (SHORT2FROMMP(mp1)) {
  27307.              case LN_ENTER:
  27308.                  switch (idLB) {
  27309.  
  27310.                  case IDL_DRIVE:
  27311.                      dbg( printf("LN_ENTER: IDL_DRIVE\n") );
  27312.                      changeDrive(hwnd,pfctl);
  27313.                      return FALSE;
  27314.  
  27315.                  case IDL_DIR:
  27316.                      dbg( printf("LN_ENTER: IDL_DIR\n") );
  27317.                      changeDir(hwnd,pfctl);
  27318.                      return FALSE;
  27319.  
  27320.                  case IDL_FILE:
  27321.                      dbg( printf("LN_ENTER: IDL_FILE\n") );
  27322.                      changeFile(hwnd,pfctl);
  27323.                      WinSendMsg(hwnd,WM_COMMAND,MPFROMSHORT(DID_OK),NULL);
  27324.                      return FALSE;
  27325.  
  27326.                  default:
  27327.                      dbg( printf("LN_ENTER: unknown list box = %04x\n",idLB) )
  27328.                      return WinDefDlgProc(hwnd, msg, mp1, mp2);
  27329.                      break;
  27330.                  }
  27331.                  break;
  27332.  
  27333.              case LN_SELECT:
  27334.                  switch (idLB) {
  27335.  
  27336.                  case IDL_DRIVE:
  27337.                      dbg( printf("LN_SELECT: IDL_DRIVE\n") );
  27338.                      it = SHORT1FROMMR(WinSendMsg(hwndFocus, LM_QUERYSELECTION
  27339.                      if (it != LIT_NONE) {
  27340.                          if (fDidOK)
  27341.                              fDidOK = FALSE;
  27342.                          else {
  27343.                              itDrive = it;
  27344.                              WinSendMsg(hwndFocus, LM_QUERYITEMTEXT,
  27345.                                  MPFROM2SHORT(it,CCHMAXPATH), MPFROMP(ach));
  27346.                              strcat(ach,pfctl->pszPattern);
  27347.                              WinSetWindowText(hwndText, ach);
  27348.                          }
  27349.                      }
  27350.                      idLB = 0;                // allow LN_SETFOCUS to work
  27351.                      return FALSE;
  27352.  
  27353.                  case IDL_DIR:
  27354.                      dbg( printf("LN_SELECT: IDL_DIR\n") );
  27355.                      it = SHORT1FROMMR(WinSendMsg(hwndFocus, LM_QUERYSELECTION
  27356.                      if (it != LIT_NONE) {
  27357.                          if (fDidOK)
  27358.                              fDidOK = FALSE;
  27359.                          else {
  27360.                              itDir = it;
  27361.                              WinSendMsg(hwndFocus, LM_QUERYITEMTEXT,
  27362.                                  MPFROM2SHORT(it,CCHMAXPATH), MPFROMP(ach));
  27363.                              strcat(ach,"\\");
  27364.                              strcat(ach,pfctl->pszPattern);
  27365.                              WinSetWindowText(hwndText, ach);
  27366.                          }
  27367.                      }
  27368.                      idLB = 0;                // allow LN_SETFOCUS to work
  27369.                      return FALSE;
  27370.  
  27371.                  case IDL_FILE:
  27372.                      dbg( printf("LN_SELECT: IDL_FILE\n") );
  27373.                      it = SHORT1FROMMR(WinSendMsg(hwndFocus, LM_QUERYSELECTION
  27374.                      if (it != LIT_NONE) {
  27375.                          if (fDidOK)
  27376.                              fDidOK = FALSE;
  27377.                          else {
  27378.                              itFile = it;
  27379.                              changeFile(hwnd,pfctl);
  27380.                          }
  27381.                      }
  27382.                      idLB = 0;                // allow LN_SETFOCUS to work
  27383.                      return FALSE;
  27384.  
  27385.                  default:
  27386.                      dbg( printf("LN_SELECT: unknown list box = %04x\n",idLB)
  27387.                      return WinDefDlgProc(hwnd, msg, mp1, mp2);
  27388.                      break;
  27389.                  }
  27390.                  break;
  27391.  
  27392.              case LN_SETFOCUS:
  27393.                  //* The following test prevents reselecting the last
  27394.                  //  selected list box item when the user is scrolling
  27395.                  //  the list box.
  27396.  
  27397.                  if (idLB == idLBPrevious)
  27398.                      break;                // no actual focus change
  27399.  
  27400.                  switch (idLB) {
  27401.  
  27402.                  case IDL_DRIVE:
  27403.                      dbg( printf("LN_SETFOCUS: IDL_DRIVE\n") );
  27404.                      hwndFocus = hwndLBDrive;
  27405.                      WinSendMsg(hwndFocus, LM_SELECTITEM,
  27406.                              MPFROMSHORT(itDrive), MPFROMSHORT(TRUE));
  27407.                      return FALSE;
  27408.  
  27409.                  case IDL_DIR:
  27410.                      dbg( printf("LN_SETFOCUS: IDL_DIR\n") );
  27411.                      hwndFocus = hwndLBDir;
  27412.                      WinSendMsg(hwndFocus, LM_SELECTITEM,
  27413.                              MPFROMSHORT(itDir), MPFROMSHORT(TRUE));
  27414.                      return FALSE;
  27415.  
  27416.                  case IDL_FILE:
  27417.                      dbg( printf("LN_SETFOCUS: IDL_FILE\n") );
  27418.                      hwndFocus = hwndLBFile;
  27419.                      WinSendMsg(hwndFocus, LM_SELECTITEM,
  27420.                              MPFROMSHORT(itFile), MPFROMSHORT(TRUE));
  27421.                      return FALSE;
  27422.  
  27423.                  default:
  27424.                      dbg( printf("LN_SETFOCUS: unknown list box = %04x\n",idLB
  27425.                      return WinDefDlgProc(hwnd, msg, mp1, mp2);
  27426.                      break;
  27427.                  }
  27428.                  break;
  27429.  
  27430.              case LN_KILLFOCUS:
  27431.                  switch (idLB) {
  27432.  
  27433.                  case IDL_DRIVE:
  27434.                      dbg( printf("LN_KILLFOCUS: IDL_DRIVE\n") );
  27435.                      hwndFocus = hwndLBDrive;
  27436.                      WinSendMsg(hwndFocus, LM_SELECTITEM,
  27437.                              MPFROMSHORT(LIT_NONE), MPFROMSHORT(FALSE));
  27438.                      return FALSE;
  27439.  
  27440.                  case IDL_DIR:
  27441.                      dbg( printf("LN_KILLFOCUS: IDL_DIR\n") );
  27442.                      hwndFocus = hwndLBDir;
  27443.                      WinSendMsg(hwndFocus, LM_SELECTITEM,
  27444.                              MPFROMSHORT(LIT_NONE), MPFROMSHORT(FALSE));
  27445.                      return FALSE;
  27446.  
  27447.                  case IDL_FILE:
  27448.                      dbg( printf("LN_KILLFOCUS: IDL_FILE\n") );
  27449.                      hwndFocus = hwndLBFile;
  27450.                      WinSendMsg(hwndFocus, LM_SELECTITEM,
  27451.                              MPFROMSHORT(LIT_NONE), MPFROMSHORT(FALSE));
  27452.                      return FALSE;
  27453.  
  27454.                  default:
  27455.                      dbg( printf("LN_KILLFOCUS: unknown list box = %04x\n",idL
  27456.                      return WinDefDlgProc(hwnd, msg, mp1, mp2);
  27457.                      break;
  27458.                  }
  27459.                  break;
  27460.  
  27461.              default:
  27462.                  dbg( printf("notify code= %04x\n",SHORT2FROMMP(mp1)) );
  27463.                  return WinDefDlgProc(hwnd, msg, mp1, mp2);
  27464.          }
  27465.          return FALSE;
  27466.  
  27467.      default:
  27468.          return WinDefDlgProc(hwnd, msg, mp1, mp2);
  27469.      }
  27470.      return FALSE;
  27471.  }
  27472.  
  27473.  
  27474.  BOOL        changeDrive(HWND hwndDlg, PFILECTL pfctl)
  27475.  {
  27476.      USHORT  it;
  27477.      USHORT  drv;
  27478.      HWND    hwndLBDrive;
  27479.      HWND    hwndText;
  27480.  
  27481.      hwndLBDrive = WinWindowFromID(hwndDlg, IDL_DRIVE);
  27482.      hwndText = WinWindowFromID(hwndDlg, IDC_TEXT);
  27483.  
  27484.      it = SHORT1FROMMR(WinSendMsg(hwndLBDrive, LM_QUERYSELECTION, 0L, 0L));
  27485.      if (it != LIT_NONE) {
  27486.          itDrive = it;
  27487.          drv = SHORT1FROMMR(WinSendMsg(hwndLBDrive, // get drive number
  27488.                          LM_QUERYITEMHANDLE, MPFROMSHORT(it), 0L));
  27489.          DosSelectDisk(drv);                // change drive
  27490.          WinSetWindowText(hwndText, pfctl->pszPattern);        // reset patter
  27491.          setDir(hwndDlg);                // update dir list
  27492.          setFile(hwndDlg);                // update file list
  27493.          setCurDir(hwndDlg);                // update current drive/dir text
  27494.          return TRUE;
  27495.      }
  27496.      return FALSE;
  27497.  }
  27498.  
  27499.  
  27500.  BOOL        changeDir(HWND hwndDlg, PFILECTL pfctl)
  27501.  {
  27502.      char    ach[CCHMAXPATH];
  27503.      HWND    hwndLBDir;
  27504.      HWND    hwndText;
  27505.      USHORT  it;
  27506.  
  27507.      hwndLBDir = WinWindowFromID(hwndDlg, IDL_DIR);
  27508.      hwndText = WinWindowFromID(hwndDlg, IDC_TEXT);
  27509.  
  27510.      it = SHORT1FROMMR(WinSendMsg(hwndLBDir, LM_QUERYSELECTION, 0L, 0L));
  27511.      if (it != LIT_NONE) {
  27512.          itDir = it;
  27513.          WinSendMsg(hwndLBDir, LM_QUERYITEMTEXT, // get dir
  27514.                          MPFROM2SHORT(it,CCHMAXPATH), MPFROMP(ach));
  27515.          DosChDir(ach, 0L);
  27516.          WinSetWindowText(hwndText, pfctl->pszPattern);        // reset patter
  27517.          setDir(hwndDlg);                // update dir list
  27518.          setFile(hwndDlg);                // update file list
  27519.          setCurDir(hwndDlg);                // update current drive/dir text
  27520.          return TRUE;
  27521.      }
  27522.      return FALSE;
  27523.  }
  27524.  
  27525.  BOOL        changeFile(HWND hwndDlg, PFILECTL pfctl)
  27526.  {
  27527.      char    ach[CCHMAXPATH];
  27528.      HWND    hwndLBFile;
  27529.      HWND    hwndText;
  27530.      USHORT  it;
  27531.  
  27532.      hwndText = WinWindowFromID(hwndDlg, IDC_TEXT);
  27533.      hwndLBFile = WinWindowFromID(hwndDlg, IDL_FILE);
  27534.  
  27535.      it = SHORT1FROMMR(WinSendMsg(hwndLBFile, LM_QUERYSELECTION, 0L, 0L));
  27536.      if (it != LIT_NONE) {
  27537.          itFile = it;
  27538.          WinSendMsg(hwndLBFile, LM_QUERYITEMTEXT, // get dir
  27539.                          MPFROM2SHORT(it,CCHMAXPATH), MPFROMP(ach));
  27540.          WinSetWindowText(hwndText, ach);  // set file name
  27541.          return TRUE;
  27542.      }
  27543.      return FALSE;
  27544.  }
  27545.  
  27546.  BOOL        setDrive(HWND hwndDlg)
  27547.  {
  27548.      char    ach[3];
  27549.      ULONG   bmlDrives;
  27550.      USHORT  drvCurrent;
  27551.      HWND    hwndLBDrive;
  27552.      USHORT  i;
  27553.      USHORT  us;
  27554.  
  27555.  
  27556.      hwndLBDrive = WinWindowFromID(hwndDlg, IDL_DRIVE);
  27557.  
  27558.      if (DosQCurDisk(&drvCurrent,&bmlDrives) != 0) {
  27559.          dbg( printf("DosQCurDisk failed!\n") );
  27560.          return FALSE;
  27561.      }
  27562.      drvCurrent--;                        // 0-based drive number
  27563.  
  27564.      ach[1] = ':';                        // init drive string
  27565.      ach[2] = '\0';
  27566.  
  27567.      WinEnableWindowUpdate(hwndLBDrive,FALSE); // turn off list box updates
  27568.      WinSendMsg(hwndLBDrive, LM_DELETEALL, NULL, NULL); // delete old entries
  27569.  
  27570.      for (i=0; bmlDrives != NULL; i++) { // get all 1 bits!
  27571.          if (bmlDrives & 1) {                // drive exists
  27572.              ach[0] = (char)(i + 'a');
  27573.              us = SHORT1FROMMR(WinSendMsg(hwndLBDrive, LM_INSERTITEM,
  27574.                      MPFROMSHORT(LIT_SORTASCENDING), MPFROMP(ach)));
  27575.              WinSendMsg(hwndLBDrive, LM_SETITEMHANDLE,         // set drive nu
  27576.                  MPFROMSHORT(us), MPFROMSHORT(i+1));
  27577.              if (i == drvCurrent) {
  27578.                  itDrive = us;                // save index for selection
  27579.              }
  27580.          }
  27581.          bmlDrives >>= 1;                // get next drive bit in bit 0
  27582.      }
  27583.  
  27584.      WinEnableWindowUpdate(hwndLBDrive,TRUE); // repaint list box
  27585.      return TRUE;
  27586.  }
  27587.  
  27588.  BOOL        setCurDir(HWND hwndDlg)
  27589.  {
  27590.      char    ach[CCHMAXPATH];
  27591.      ULONG   bmlDrives;
  27592.      USHORT  cch;
  27593.      USHORT  drvCurrent;
  27594.      HWND    hwndCurDir;
  27595.      USHORT  rc;
  27596.  
  27597.      rc = DosQCurDisk(&drvCurrent,&bmlDrives);        // get current drive
  27598.  
  27599.      ach[0] = (char)((char)drvCurrent + 'a' - (char)1) ; // make drive letter
  27600.      ach[1] = ':';                        // rest of drive string
  27601.      ach[2] = '\\';
  27602.  
  27603.      cch = CCHMAXPATH-3;                            // room for drive string
  27604.  
  27605.      rc = DosQCurDir(drvCurrent, &ach[3], &cch);
  27606.  
  27607.      hwndCurDir = WinWindowFromID(hwndDlg, IDC_CURDIR);
  27608.      WinSetWindowText(hwndCurDir,ach);        // set current drive/dir text
  27609.      return TRUE;
  27610.  }
  27611.  
  27612.  
  27613.  BOOL        setDir(HWND hwndDlg)
  27614.  {
  27615.      char            ach[20];
  27616.      static USHORT   attr;
  27617.      USHORT            cch;
  27618.      HWND            hwndLBDir;
  27619.  
  27620.      hwndLBDir  = WinWindowFromID(hwndDlg, IDL_DIR);
  27621.  
  27622.      WinEnableWindowUpdate(hwndLBDir,FALSE); // turn off list box updates
  27623.      WinSendMsg(hwndLBDir, LM_DELETEALL, NULL, NULL); // delete old entries
  27624.  
  27625.      // get all directories
  27626.  
  27627.      strcpy(ach,"*.*");
  27628.      attr = 0x37;
  27629.      for (cch = beginSearch(ach,&attr);
  27630.           cch != 0;
  27631.           cch = nextSearch(ach,&attr)) {
  27632.          if (attr & 0x0010) {                // only get directories
  27633.          //  if ((cch > 1) || (ach[0] != '.')) { // do all but "."
  27634.                  WinSendMsg(hwndLBDir, LM_INSERTITEM,
  27635.                      MPFROMSHORT(LIT_SORTASCENDING), MPFROMP(ach));
  27636.          //  }
  27637.          }
  27638.      }
  27639.      endSearch();
  27640.  
  27641.      WinEnableWindowUpdate(hwndLBDir,TRUE); // repaint list box
  27642.      itDir = 1;
  27643.      return TRUE;
  27644.  }
  27645.  
  27646.  
  27647.  BOOL        setFile(HWND hwndDlg)
  27648.  {
  27649.      char            ach[20];
  27650.      static USHORT   attr;
  27651.      USHORT            cch;
  27652.      HWND            hwndLBFile;
  27653.      HWND            hwndText;
  27654.  
  27655.      hwndLBFile = WinWindowFromID(hwndDlg, IDL_FILE);
  27656.      hwndText   = WinWindowFromID(hwndDlg, IDC_TEXT);
  27657.  
  27658.      WinEnableWindowUpdate(hwndLBFile,FALSE); // turn off list box updates
  27659.      WinSendMsg(hwndLBFile, LM_DELETEALL, NULL, NULL); // delete old entries
  27660.  
  27661.      // get only files that match user's pattern
  27662.  
  27663.      WinQueryWindowText(hwndText,CCHMAXPATH,ach);
  27664.      dbg( printf("file pattern = %s\n",ach) );
  27665.      attr = 0x27;                        // do all but directories
  27666.      for (cch = beginSearch(ach,&attr);
  27667.           cch != 0;
  27668.           cch = nextSearch(ach,&attr) ) {
  27669.          WinSendMsg(hwndLBFile, LM_INSERTITEM,
  27670.                  MPFROMSHORT(LIT_SORTASCENDING), MPFROMP(ach));
  27671.  
  27672.      }
  27673.      endSearch();
  27674.      WinEnableWindowUpdate(hwndLBFile,TRUE); // repaint list box
  27675.      itFile = 1;                            // default selection
  27676.  
  27677.      return TRUE;
  27678.  }
  27679.  
  27680.  
  27681.  USHORT        beginSearch(char *psz, USHORT *pattr)
  27682.  {
  27683.      FILEFINDBUF            findbuf;
  27684.      USHORT            cf;
  27685.      USHORT            rc;
  27686.  
  27687.      cf = 1;                            // only return 1 file
  27688.      hdir = 0xFFFF;                    // create a search handle
  27689.  
  27690.      rc = DosFindFirst(psz,            // file specification
  27691.                        &hdir,            // pointer to variable for handle
  27692.                        *pattr,            // search attribute (everything)
  27693.                        &findbuf,            // pointer to result buffer
  27694.                        sizeof(FILEFINDBUF), // length of result buffer
  27695.                        &cf,            // files to find/files found
  27696.                        0L);            // Must be zero
  27697.  
  27698.      if (cf != 0) {
  27699.          psz[findbuf.cchName] = '\0';        // terminate name
  27700.          strncpy(psz,findbuf.achName,findbuf.cchName); // copy name to caller
  27701.          *pattr = findbuf.attrFile;
  27702.          return findbuf.cchName;
  27703.      }
  27704.      return 0;
  27705.  }
  27706.  
  27707.  
  27708.  USHORT        nextSearch(char *psz, USHORT *pattr)
  27709.  {
  27710.      FILEFINDBUF            findbuf;
  27711.      USHORT            cf;
  27712.      USHORT            rc;
  27713.  
  27714.      cf = 1;            // only return 1 file
  27715.  
  27716.      rc = DosFindNext(hdir,            // pointer to variable for handle
  27717.                       &findbuf,            // pointer to result buffer
  27718.                       sizeof(FILEFINDBUF), // length of result buffer
  27719.                       &cf);            // files to find/files found
  27720.  
  27721.      if (cf != 0) {
  27722.          psz[findbuf.cchName] = '\0'; // terminate name
  27723.          strncpy(psz,findbuf.achName,findbuf.cchName); // copy name to caller
  27724.          *pattr = findbuf.attrFile;
  27725.          return findbuf.cchName;
  27726.      }
  27727.      return 0;
  27728.  }
  27729.  
  27730.  
  27731.  void        endSearch(void)
  27732.  {
  27733.      DosFindClose(hdir);
  27734.  }
  27735.  
  27736.  
  27737.  /***        trimBlanks - trim off leading and trailing blanks
  27738.  *
  27739.  *        ENTRY        psz - string to be trimmed
  27740.  */
  27741.  
  27742.  char * trimBlanks(char *psz)
  27743.  {
  27744.      char *pch;
  27745.      char *pchDst;
  27746.      char *pchRight;
  27747.  
  27748.      //        Find right-most non-blank character
  27749.  
  27750.      for (pch = psz+strlen(psz)-1;        // start at last character
  27751.           (pch >= psz) && (*pch == ' '); // scan backward to non-blank
  27752.          pch--)
  27753.              ;
  27754.  
  27755.      *(pch+1) = '\0';                        // trim trailing blanks
  27756.  
  27757.      pchRight = pch;
  27758.  
  27759.      // Find left-most non-blank character
  27760.  
  27761.      for (pch = psz;                        // start at first character
  27762.           (pch <= pchRight) && (*pch == ' '); // scan forward to non-blank
  27763.           pch++)
  27764.              ;
  27765.  
  27766.      // Shift string left to trim leading blanks
  27767.  
  27768.      if (pch > psz) {                        // leading blanks to trim
  27769.          pchRight++;                        // grab traling null
  27770.          pchDst = psz;                        // do not destroy psz
  27771.          while (pchDst <= pchRight)
  27772.              *pchDst++ = *pch++;                // shift string left
  27773.      }
  27774.      return psz;
  27775.  }
  27776.  
  27777.  
  27778.  FILE.C
  27779.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\OPENDLG\FILE.C
  27780.  
  27781.  /*
  27782.      FILE.C -- Open/Save As Dialog Box library routines
  27783.      Created by Microsoft Corporation, 1989
  27784.  */
  27785.  #define  INCL_DOS
  27786.  #define  INCL_DOSQUEUES
  27787.  #include "tool.h"
  27788.  
  27789.  
  27790.  /****************************************************************************
  27791.  * This function is the Open dialog box window procedure.  It handles input,
  27792.  * allows the user to change directories, checks for legal filenames, opens
  27793.  * specified files, appends default extensions and returns the file's name.
  27794.  *
  27795.  * The return values are
  27796.  *   TDF_INVALID - Library error (internal error),
  27797.  *   TDF_NOOPEN  - User hits cancel
  27798.  *   TDF_NEWOPEN - Created new file (file left open)
  27799.  *   TDF_OLDOPEN - Opened existing file (file left open)
  27800.  \****************************************************************************
  27801.  
  27802.  MRESULT EXPENTRY DlgOpenWndProc(hwnd, msg, mp1, mp2)
  27803.  HWND hwnd;
  27804.  USHORT msg;
  27805.  MPARAM mp1;
  27806.  MPARAM mp2;
  27807.      {
  27808.      PDLF pdlf;
  27809.      PSZ  lpchFile;
  27810.      CHAR sz[MAX_FNAME_LEN];
  27811.  
  27812.      switch (msg)
  27813.          {
  27814.      case WM_INITDLG:
  27815.          /* initialize dialog box */
  27816.          DlgInitOpen(hwnd, LONGFROMMP(mp2));
  27817.  
  27818.          /* fill static field with path name and fill list box with
  27819.             filenames that lMatch spec */
  27820.          if (!DlgDirList(hwnd, ((PDLF)(mp2))->pszExt+1, ID_DIRLIST,
  27821.                          ID_FILELIST, ID_PATH, ((PDLF)(mp2))->rgbFlags))
  27822.              /* NOTE: shouldn't we post a message if something screws up? */
  27823.              WinDismissDlg(hwnd, TDF_INVALID);
  27824.          break;
  27825.  
  27826.      case WM_COMMAND:
  27827.          pdlf = (PDLF) WinQueryWindowULong(hwnd, 0);
  27828.          switch (SHORT1FROMMP(mp1))
  27829.              {
  27830.          case MBID_OK:
  27831.              /* Open button pressed */
  27832.              /* get name from edit box */
  27833.              WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  27834.                  CBROOTNAMEMAX, (PSZ)pdlf->szFileName);
  27835.              Upper((PSZ)pdlf->szFileName);
  27836.              if (lstrlen((PSZ)pdlf->szFileName))
  27837.                  DlgOpenName(hwnd, pdlf);
  27838.              break;
  27839.  
  27840.          case MBID_CANCEL:
  27841.              /* Cancel button pressed, dismiss dialog box */
  27842.              WinDismissDlg(hwnd, TDF_NOOPEN);
  27843.              break;
  27844.  
  27845.          case MBID_HELP:
  27846.              /* Help button pressed */
  27847.              WinMessageBox( HWND_DESKTOP
  27848.                           , hwnd
  27849.                           , pdlf->pszInstructions
  27850.                           , pdlf->pszTitle
  27851.                           , NULL
  27852.                           , MB_OK | MB_APPLMODAL );
  27853.              break;
  27854.              }
  27855.          break;
  27856.  
  27857.      case WM_CONTROL:
  27858.          pdlf = (PDLF) WinQueryWindowULong(hwnd, 0);
  27859.          switch (SHORT1FROMMP(mp1))
  27860.              {
  27861.          case ID_DIRLIST:
  27862.              /* user clicked in directory list box */
  27863.              switch (SHORT2FROMMP(mp1))
  27864.                  {
  27865.              case LN_SELECT:
  27866.                  /* single click case */
  27867.                  /* get current edit string */
  27868.                  WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  27869.                                     CBROOTNAMEMAX, (PSZ)sz);
  27870.                  Upper((PSZ)sz);
  27871.  
  27872.                  /* get selected string */
  27873.                  if (DlgDirSelect(hwnd, (PSZ)pdlf->szFileName, ID_DIRLIST))
  27874.                      {
  27875.                      /* if edit field contains wild card, then append file
  27876.                         part to selected directory, otherwise append
  27877.                         last wildcard search spec */
  27878.                      lpchFile = FileInPath((PSZ)sz);
  27879.                      lstrcat( (PSZ)pdlf->szFileName
  27880.                             , DlgSearchSpec( lpchFile)
  27881.                               ? lpchFile
  27882.                               : (PSZ)pdlf->szLastWild );
  27883.                      /* set edit box to resulting name */
  27884.                      WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT),
  27885.                                       (PSZ)pdlf->szFileName);
  27886.                      }
  27887.                  break;
  27888.  
  27889.              case LN_ENTER:
  27890.                  /* get text from edit box */
  27891.                  WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  27892.                                     CBROOTNAMEMAX, (PSZ)pdlf->szFileName);
  27893.                  Upper((PSZ)pdlf->szFileName);
  27894.                  if( DlgSearchSpec( (PSZ)pdlf->szFileName))
  27895.                      {
  27896.                      DlgDirList( hwnd
  27897.                                , (PSZ)pdlf->szFileName
  27898.                                , ID_DIRLIST
  27899.                                , ID_FILELIST
  27900.                                , ID_PATH
  27901.                                , pdlf->rgbFlags );
  27902.                      lstrcpy( (PSZ)pdlf->szLastWild
  27903.                             , FileInPath( (PSZ)pdlf->szFileName));
  27904.                      WinSetWindowText( WinWindowFromID( hwnd, ID_EDIT)
  27905.                                      , (PSZ)pdlf->szFileName );
  27906.                      }
  27907.                  break;
  27908.                  }
  27909.              break;
  27910.  
  27911.          case ID_FILELIST:
  27912.              /* user clicked in file list box */
  27913.              switch (SHORT2FROMMP(mp1))
  27914.                  {
  27915.              case LN_SELECT:
  27916.                  /* single click case */
  27917.  
  27918.                  /* get current edit string */
  27919.                  /* if it contains a wildcard, save it before obliteration */
  27920.                  WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  27921.                                     CBROOTNAMEMAX, (PSZ)sz);
  27922.                  Upper((PSZ)sz);
  27923.                  if( DlgSearchSpec( (PSZ)sz))
  27924.                      lstrcpy( (PSZ)pdlf->szLastWild, FileInPath( (PSZ)sz));
  27925.  
  27926.                  /* get selected file name */
  27927.                  DlgDirSelect(hwnd, (PSZ)pdlf->szFileName, ID_FILELIST);
  27928.                  /* set edit box to resulting name */
  27929.                  WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT),
  27930.                                   (PSZ)pdlf->szFileName);
  27931.                  break;
  27932.  
  27933.              case LN_ENTER:
  27934.                  /* double click case, single click already processed */
  27935.                  DlgOpenName(hwnd, pdlf);
  27936.                  break;
  27937.                  }
  27938.              break;
  27939.              }
  27940.          break;
  27941.  
  27942.      default:
  27943.          return (WinDefDlgProc(hwnd, msg, mp1, mp2));
  27944.          }
  27945.  
  27946.      return (MRFROMLONG(0L));  /* message processed */
  27947.      }
  27948.  
  27949.  
  27950.  
  27951.  
  27952.  /****************************************************************************
  27953.  * This function stores the pdlf in the dialog window structure, sets
  27954.  * the title and instruction texts and limits the text size.
  27955.  \****************************************************************************
  27956.  
  27957.  VOID PASCAL DlgInitOpen (hwnd, lpParm)
  27958.  HWND hwnd;
  27959.  ULONG lpParm;
  27960.      {
  27961.      PDLF pdlf;
  27962.  
  27963.      /* Set pdlf local to window */
  27964.      pdlf = (PDLF) lpParm;
  27965.      WinSetWindowULong(hwnd, 0, lpParm);
  27966.  
  27967.      /* set edit box text size limit */
  27968.      WinSendDlgItemMsg(hwnd, ID_EDIT, EM_SETTEXTLIMIT, (MPARAM)CBROOTNAMEMAX,
  27969.  
  27970.      /* set edit window to search spec */
  27971.      if (pdlf->pszExt != (PSZ)NULL)
  27972.          WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT), pdlf->pszExt+1);
  27973.  
  27974.      /* set title window */
  27975.      if (pdlf->pszTitle != (PSZ)NULL)
  27976.          WinSetWindowText(WinWindowFromID(hwnd, FID_TITLEBAR), pdlf->pszTitle)
  27977.      }
  27978.  
  27979.  
  27980.  
  27981.  
  27982.  /****************************************************************************
  27983.  * This function processes the currently selected name in the open dialog
  27984.  * box.  If the name represents a directory, the current directory is
  27985.  * changed to that one and the corresponding files are displayed.  If the
  27986.  * name is a file, then it is opened.
  27987.  \****************************************************************************
  27988.  
  27989.  VOID PASCAL DlgOpenName(hwnd, pdlf)
  27990.  HWND hwnd;
  27991.  PDLF pdlf;
  27992.      {
  27993.      PSZ  lpch;
  27994.      USHORT wVal;
  27995.      CHAR sz[MAX_FNAME_LEN];
  27996.  
  27997.      /* try using current name as a directory */
  27998.      lstrcpy((PSZ)sz, (PSZ)pdlf->szFileName);
  27999.      if (!DlgSearchSpec((PSZ)sz))
  28000.          DlgAddSearchExt(pdlf, (PSZ)sz);
  28001.      if (DlgDirList(hwnd, (PSZ)sz, ID_DIRLIST, ID_FILELIST, ID_PATH,
  28002.                     pdlf->rgbFlags))
  28003.          {
  28004.          /* name was a directory, extract and set file name */
  28005.          lpch = FileInPath((PSZ)sz);
  28006.          lstrcpy((PSZ)pdlf->szFileName, lpch);
  28007.          WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28008.                           (PSZ)pdlf->szFileName);
  28009.          }
  28010.      else
  28011.          /* try to open name as a file */
  28012.          if ((wVal = DlgOpenFile(pdlf, hwnd)) != TDF_NOOPEN)
  28013.              WinDismissDlg(hwnd, wVal);
  28014.      }
  28015.  
  28016.  
  28017.  
  28018.  
  28019.  /****************************************************************************
  28020.  * This function is the SaveAs dialog box window procedure.  It handles input,
  28021.  * tests for legal filenames and uses message boxes to report any problems.
  28022.  *
  28023.  * Return values are:
  28024.  *     TDF_INVALID - Library error (internal error),
  28025.  *     TDF_NOOPEN  - User hits cancel
  28026.  *   Specific for DLG_NOOPEN
  28027.  *     TDF_NEWSAVE - user wants to save to a new file (file not created)
  28028.  *     TDF_OLDSAVE - user wants to save over existing file (file not opened)
  28029.  *   else
  28030.  *     TDF_NEWSAVE - user wants to save to a new file (file left open)
  28031.  *     TDF_OLDSAVE - user wants to save over existing file (file left open)
  28032.  \****************************************************************************
  28033.  
  28034.  MRESULT EXPENTRY DlgSaveAsWndProc(hwnd, msg, mp1, mp2)
  28035.  HWND   hwnd;
  28036.  USHORT msg;
  28037.  MPARAM mp1;
  28038.  MPARAM mp2;
  28039.      {
  28040.      PDLF    pdlf;
  28041.      PSZ     lpchFile;
  28042.      CHAR    sz[MAX_FNAME_LEN];
  28043.  
  28044.      switch (msg)
  28045.          {
  28046.      case WM_INITDLG:
  28047.          /* Store pdlf, set instructions, limit text size */
  28048.          DlgInitSaveAs(hwnd, LONGFROMMP(mp2));
  28049.  
  28050.          /* fill static field with path name and fill list box with
  28051.             filenames that lMatch spec */
  28052.          if (!DlgDirList(hwnd, ((PDLF)(mp2))->pszExt+1, ID_DIRLIST,
  28053.                          ID_FILELIST, ID_PATH, ((PDLF)(mp2))->rgbFlags))
  28054.              /* NOTE: shouldn't we post a message if something screws up? */
  28055.              WinDismissDlg(hwnd, TDF_INVALID);
  28056.          break;
  28057.  
  28058.      case WM_COMMAND:
  28059.          pdlf = (PDLF) WinQueryWindowULong(hwnd, 0);
  28060.          switch (SHORT1FROMMP(mp1))
  28061.             {
  28062.          case MBID_OK:
  28063.              /* get text from edit box */
  28064.              WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28065.                                 CBROOTNAMEMAX, (PSZ)pdlf->szFileName);
  28066.              Upper((PSZ)pdlf->szFileName);
  28067.              if( DlgSearchSpec( (PSZ)pdlf->szFileName))
  28068.                  {
  28069.                  DlgDirList( hwnd
  28070.                            , (PSZ)pdlf->szFileName
  28071.                            , ID_DIRLIST
  28072.                            , ID_FILELIST
  28073.                            , ID_PATH
  28074.                            , pdlf->rgbFlags );
  28075.                  lstrcpy( (PSZ)pdlf->szLastWild
  28076.                         , FileInPath( (PSZ)pdlf->szFileName));
  28077.                  lstrcpy( (PSZ)pdlf->szFileName, (PSZ)pdlf->szLastFile);
  28078.                  WinSetWindowText( WinWindowFromID( hwnd, ID_EDIT)
  28079.                                  , (PSZ)pdlf->szFileName );
  28080.                  }
  28081.              else if( lstrlen( (PSZ)pdlf->szFileName))
  28082.                  DlgSaveAsName( hwnd, pdlf);
  28083.              break;
  28084.  
  28085.          case MBID_CANCEL:
  28086.              WinDismissDlg(hwnd, TDF_NOSAVE);
  28087.              break;
  28088.  
  28089.          case MBID_HELP:
  28090.              /* Help button pressed */
  28091.              WinMessageBox( HWND_DESKTOP
  28092.                           , hwnd
  28093.                           , pdlf->pszInstructions
  28094.                           , pdlf->pszTitle
  28095.                           , NULL
  28096.                           , MB_OK | MB_APPLMODAL );
  28097.              break;
  28098.              }
  28099.          break;
  28100.  
  28101.      case WM_CONTROL:
  28102.          pdlf = (PDLF) WinQueryWindowULong(hwnd, 0);
  28103.          switch (SHORT1FROMMP(mp1))
  28104.              {
  28105.          case ID_DIRLIST:
  28106.              /* user clicked in directory list box */
  28107.              switch (SHORT2FROMMP(mp1))
  28108.                  {
  28109.              case LN_SELECT:
  28110.                  /* single click case */
  28111.                  /* get current edit string */
  28112.                  WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28113.                                     CBROOTNAMEMAX, (PSZ)sz);
  28114.                  Upper((PSZ)sz);
  28115.  
  28116.                  /* get selected string */
  28117.                  if (DlgDirSelect(hwnd, (PSZ)pdlf->szFileName, ID_DIRLIST))
  28118.                      {
  28119.                      /* if edit field contains wild card, then append file
  28120.                         part to selected directory, otherwise append
  28121.                         last wildcard search spec */
  28122.                      lpchFile = FileInPath((PSZ)sz);
  28123.                      if( DlgSearchSpec( lpchFile))
  28124.                          {
  28125.                          lstrcat( (PSZ)pdlf->szFileName, lpchFile );
  28126.                          lstrcpy( (PSZ)pdlf->szLastWild, lpchFile);
  28127.                          }
  28128.                      else
  28129.                          {
  28130.                          lstrcat( (PSZ)pdlf->szFileName, (PSZ)pdlf->szLastWild
  28131.                          lstrcpy( (PSZ)pdlf->szLastFile, lpchFile);
  28132.                          }
  28133.                      /* set edit box to resulting name */
  28134.                      WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28135.                                       (PSZ)pdlf->szFileName);
  28136.                      }
  28137.                  break;
  28138.  
  28139.              case LN_ENTER:
  28140.                  /* get text from edit box */
  28141.                  WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28142.                                     CBROOTNAMEMAX, (PSZ)pdlf->szFileName);
  28143.                  Upper((PSZ)pdlf->szFileName);
  28144.                  if( DlgSearchSpec( (PSZ)pdlf->szFileName))
  28145.                      {
  28146.                      DlgDirList( hwnd
  28147.                                , (PSZ)pdlf->szFileName
  28148.                                , ID_DIRLIST
  28149.                                , ID_FILELIST
  28150.                                , ID_PATH
  28151.                                , pdlf->rgbFlags );
  28152.                      lstrcpy( (PSZ)pdlf->szLastWild
  28153.                             , FileInPath( (PSZ)pdlf->szFileName));
  28154.                      lstrcpy( (PSZ)pdlf->szFileName, (PSZ)pdlf->szLastFile);
  28155.                      WinSetWindowText( WinWindowFromID( hwnd, ID_EDIT)
  28156.                                      , (PSZ)pdlf->szFileName );
  28157.                      }
  28158.                  break;
  28159.                  }
  28160.              break;
  28161.  
  28162.          case ID_FILELIST:
  28163.              /* user clicked in file list box */
  28164.              switch (SHORT2FROMMP(mp1))
  28165.                  {
  28166.              case LN_SELECT:
  28167.                  /* single click case */
  28168.  
  28169.                  /* get current edit string */
  28170.                  /* if it contains a wildcard, save it before obliteration */
  28171.                  WinQueryWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28172.                                     CBROOTNAMEMAX, (PSZ)sz);
  28173.                  Upper((PSZ)sz);
  28174.                  if( DlgSearchSpec( (PSZ)sz))
  28175.                      lstrcpy( (PSZ)pdlf->szLastWild, FileInPath( (PSZ)sz));
  28176.  
  28177.                  /* get selected file name */
  28178.                  DlgDirSelect(hwnd, (PSZ)pdlf->szFileName, ID_FILELIST);
  28179.                  /* set edit box to resulting name */
  28180.                  WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT),
  28181.                                   (PSZ)pdlf->szFileName);
  28182.                  break;
  28183.  
  28184.              case LN_ENTER:
  28185.                  /* double click case, single click already processed */
  28186.                  DlgSaveAsName(hwnd, pdlf);
  28187.                  break;
  28188.                  }
  28189.              break;
  28190.              }
  28191.          break;
  28192.  
  28193.      default:
  28194.          return (WinDefDlgProc(hwnd, msg, mp1, mp2));
  28195.          }
  28196.  
  28197.      return (MRFROMLONG(0L));    /* message processed */
  28198.      }
  28199.  
  28200.  
  28201.  
  28202.  /****************************************************************************
  28203.  /*
  28204.  /* This function attempts to open a file for writing.  It queries if over-
  28205.  /* write is OK if the file already exists.
  28206.  /*
  28207.  /****************************************************************************
  28208.  VOID PASCAL DlgSaveAsName( hwnd, pdlf)
  28209.  HWND  hwnd;
  28210.  PDLF  pdlf;
  28211.      {
  28212.      USHORT  usTdf;
  28213.  
  28214.      /* add extension if there is not one already */
  28215.      AddExt((PSZ)pdlf->szFileName, pdlf->pszExt);
  28216.      /* test file name legality */
  28217.      if (!DlgParseFile((PSZ)pdlf->szFileName,
  28218.                        (PSZ)pdlf->szOpenFile, FALSE, FALSE))
  28219.          {
  28220.          /* illegal filename */
  28221.          DlgAlertBox(hwnd, IDS_IFN, pdlf,
  28222.                      MB_OK | MB_ICONEXCLAMATION);
  28223.          return;
  28224.          }
  28225.      usTdf = TDF_NEWSAVE;
  28226.      /* test if file already exists */
  28227.      if (DlgParseFile((PSZ)pdlf->szFileName,
  28228.                       (PSZ)pdlf->szOpenFile, TRUE, FALSE))
  28229.          {
  28230.          /* overwrite? */
  28231.          if (DlgAlertBox(hwnd, IDS_REF, pdlf,
  28232.                          MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION)
  28233.              == MBID_NO)
  28234.              return;
  28235.          usTdf = TDF_OLDSAVE;
  28236.          }
  28237.      if (!(pdlf->rgbAction & DLG_NOOPEN) &&
  28238.          !(OpenFile( (PSZ)pdlf->szFileName
  28239.                    , pdlf->phFile
  28240.                    , (PSZ)pdlf->szOpenFile
  28241.                    , OF_WRITE)))
  28242.          {
  28243.          DlgAlertBox(hwnd, IDS_EOF, pdlf,
  28244.                      MB_OK | MB_ICONEXCLAMATION);
  28245.          return;
  28246.          }
  28247.      WinDismissDlg(hwnd, usTdf);
  28248.      }
  28249.  
  28250.  
  28251.  
  28252.  /****************************************************************************
  28253.  * This function initializes the SaveAs dialog box.  It puts the current
  28254.  * directory string in the ID_PATH field and initializes the edit box
  28255.  * with the proposed filename.  It is the simple relative file name if current
  28256.  * dir == pdlf->szOpenFile.  Otherwise, it is the fully qualified name.
  28257.  \****************************************************************************
  28258.  
  28259.  VOID PASCAL DlgInitSaveAs (hwnd, lpParm)
  28260.  HWND hwnd;
  28261.  ULONG lpParm;
  28262.      {
  28263.      PDLF pdlf;
  28264.      CHAR sz[MAX_FNAME_LEN];
  28265.      PSZ  lpszFile, lpszFN, lpszCD;
  28266.  
  28267.      /* set pdlf local to window */
  28268.      pdlf = (PDLF) lpParm;
  28269.      WinSetWindowULong(hwnd, 0, lpParm);
  28270.  
  28271.      /* set edit box text size limit */
  28272.      WinSendDlgItemMsg(hwnd, ID_EDIT, EM_SETTEXTLIMIT, (MPARAM)CBROOTNAMEMAX,
  28273.  
  28274.      /* set title window */
  28275.      if (pdlf->pszTitle != (PSZ)NULL)
  28276.          WinSetWindowText(WinWindowFromID(hwnd, FID_TITLEBAR), pdlf->pszTitle)
  28277.  
  28278.      /* set szLastWild to search spec */
  28279.      if (pdlf->pszExt != (PSZ)NULL)
  28280.          lstrcpy( (PSZ)pdlf->szLastWild, (PSZ)pdlf->pszExt+1 );
  28281.  
  28282.      /* get current directory */
  28283.      DosSearchPath(0, (PSZ)szDot, (PSZ)szStarStar, (PSZ)sz, MAX_FNAME_LEN);
  28284.      lpszFile = FileInPath((PSZ)sz);
  28285.      if (lpszFile > (PSZ)sz + 3)
  28286.          lpszFile--;
  28287.      *lpszFile = '\0';
  28288.  
  28289.      /* compare path part name to previously opened file name and
  28290.         make the file name relative if they are the same */
  28291.      lpszFN = (PSZ)pdlf->szOpenFile;
  28292.      lpszCD = (PSZ)sz;
  28293.      lpszFile = FileInPath((PSZ)pdlf->szOpenFile);
  28294.      while (lpszFN < lpszFile && *lpszFN == *lpszCD)
  28295.          {
  28296.          lpszFN = NextChar(lpszFN);
  28297.          lpszCD = NextChar(lpszCD);
  28298.          }
  28299.      if (*lpszCD)
  28300.          lpszFN = (PSZ)pdlf->szOpenFile;
  28301.      else if (*lpszFN == '\\')
  28302.          lpszFN = NextChar(lpszFN);
  28303.      Upper( lpszFN);
  28304.      WinSetWindowText(WinWindowFromID(hwnd, ID_EDIT), lpszFN);
  28305.      lstrcpy( (PSZ)pdlf->szLastFile, lpszFN);
  28306.  
  28307.      /* set current path field */
  28308.      WinSetWindowText(WinWindowFromID(hwnd, ID_PATH),
  28309.                       DlgFitPathToBox(hwnd, ID_PATH, (PSZ)sz));
  28310.      }
  28311.  
  28312.  
  28313.  
  28314.  
  28315.  /****************************************************************************
  28316.  * This function returns the filename part of the given path string.
  28317.  \****************************************************************************
  28318.  
  28319.  PSZ  EXPENTRY FileInPath(lpsz)
  28320.  PSZ  lpsz;
  28321.      {
  28322.      PSZ  lpch;
  28323.  
  28324.      /* strip path/drive specification from name if there is one */
  28325.      lpch = lpsz + lstrlen(lpsz);
  28326.      while (lpch > lpsz)
  28327.          {
  28328.          lpch = PrevChar(lpsz, lpch);
  28329.          if (*lpch == '\\' || *lpch == ':')
  28330.              {
  28331.              lpch = NextChar(lpch);
  28332.              break;
  28333.              }
  28334.          }
  28335.      return(lpch);
  28336.      }
  28337.  
  28338.  
  28339.  
  28340.  
  28341.  /****************************************************************************
  28342.  * This function adds the extension to a file name if it is missing.
  28343.  \****************************************************************************
  28344.  
  28345.  VOID EXPENTRY AddExt(lpsz, lpszExt)
  28346.  PSZ  lpsz;
  28347.  PSZ  lpszExt;
  28348.      {
  28349.      PSZ  lpch;
  28350.  
  28351.      lpch = lpsz + lstrlen(lpsz);
  28352.      while (*lpch != '.' && *lpch != '\\' && *lpch != ':' && lpch > lpsz)
  28353.          lpch = PrevChar(lpsz, lpch);
  28354.  
  28355.      if (*lpch != '.')
  28356.          lstrcat(lpsz, (PSZ)(lpszExt+2));
  28357.      }
  28358.  
  28359.  
  28360.  
  28361.  
  28362.  /****************************************************************************
  28363.  * This function adds the "appropriate" extension to a filename, partial
  28364.  * filename, search spec or partial search spec.
  28365.  \****************************************************************************
  28366.  
  28367.  VOID PASCAL DlgAddSearchExt(pdlf, lpszEdit)
  28368.  PDLF pdlf;
  28369.  PSZ  lpszEdit;
  28370.      {
  28371.      PSZ  lpchLast;
  28372.  
  28373.      lpchLast = PrevChar(lpszEdit, lpszEdit + lstrlen(lpszEdit));
  28374.      if (*lpchLast == '\\' || *lpchLast == ':')
  28375.          lstrcat(lpszEdit, pdlf->pszExt + 1);
  28376.      else
  28377.          lstrcat(lpszEdit, pdlf->pszExt);
  28378.      }
  28379.  
  28380.  
  28381.  
  28382.  
  28383.  /****************************************************************************
  28384.  * This function returns TRUE if lpsz contains a wildcard character '*' or '?'
  28385.  \****************************************************************************
  28386.  
  28387.  BOOL PASCAL DlgSearchSpec(lpsz)
  28388.  PSZ  lpsz;
  28389.     {
  28390.      for (; *lpsz; lpsz = NextChar(lpsz))
  28391.          if (*lpsz == '*' || *lpsz == '?')
  28392.              return TRUE;
  28393.      return FALSE;
  28394.     }
  28395.  
  28396.  
  28397.  
  28398.  
  28399.  /****************************************************************************
  28400.  * This function displays an error or warning msg.
  28401.  \****************************************************************************
  28402.  
  28403.  int PASCAL DlgAlertBox(hwnd, ids, pdlf, wStyle)
  28404.  HWND hwnd;
  28405.  int ids;
  28406.  PDLF pdlf;
  28407.  USHORT wStyle;
  28408.      {
  28409.      /* note:  5th param is idHelp */
  28410.      return (AlertBox(hwnd, ids, (PSZ)pdlf->szFileName, pdlf->pszAppName,
  28411.                           NULL, wStyle | MB_APPLMODAL));
  28412.      }
  28413.  
  28414.  
  28415.  FILE1.C
  28416.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\OPENDLG\FILE1.C
  28417.  
  28418.  /*
  28419.      FILE1.C -- Dialog Directory Listbox and Open File functions
  28420.      Created by Microsoft Corporation, 1989
  28421.  */
  28422.  
  28423.  #define  INCL_DOS
  28424.  #include "tool.h"
  28425.  
  28426.  /****************************************************************************
  28427.  * This function builds a directory list in a list box.
  28428.  \****************************************************************************
  28429.  
  28430.  int FAR PASCAL DlgDirList(hwnd, lpszPath, idDirList, idFileList,
  28431.                            idStaticPath, attr)
  28432.  HWND hwnd;
  28433.  PSZ  lpszPath;
  28434.  int idDirList;
  28435.  int idFileList;
  28436.  int idStaticPath;
  28437.  USHORT attr;
  28438.      {
  28439.      CHAR szPath[MAX_FNAME_LEN];
  28440.      CHAR chTmp;
  28441.      PSZ  lpszFile, lpszNull;
  28442.      HPOINTER hPointer;
  28443.  
  28444.      /* ensure path is legal and expand to full search path */
  28445.      if (!DlgParseFile(lpszPath, (PSZ)szPath, FALSE, TRUE))
  28446.          return FALSE;
  28447.  
  28448.      /* set pointer to hours glass */
  28449.      hPointer = WinQueryPointer(HWND_DESKTOP);
  28450.      WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, F
  28451.  
  28452.      /* set current drive */
  28453.      DosSelectDisk(*szPath - 'A' + 1);
  28454.  
  28455.      /* temporarily put zero after directory spec and set current directory */
  28456.      lpszFile = FileInPath((PSZ)szPath);
  28457.      lpszNull = lpszFile;
  28458.      if (lpszNull > (PSZ)szPath + 3)
  28459.          lpszNull--;
  28460.      chTmp = *lpszNull;
  28461.      *lpszNull = '\0';
  28462.      DosChDir((PSZ)szPath, 0l);
  28463.      if (idStaticPath)
  28464.          WinSetWindowText(WinWindowFromID(hwnd, idStaticPath),
  28465.                           DlgFitPathToBox(hwnd, idStaticPath, (PSZ)szPath));
  28466.      *lpszNull = chTmp;
  28467.  
  28468.      /* fill list box with file names */
  28469.      if (idDirList && idFileList)
  28470.          {
  28471.          /* fill them up with new entries */
  28472.          DlgFillListBoxes(hwnd, idDirList, idFileList, attr, lpszFile);
  28473.          }
  28474.  
  28475.      /* reset pointer to previous figure */
  28476.      WinSetPointer(HWND_DESKTOP, hPointer);
  28477.  
  28478.      return TRUE;
  28479.      }
  28480.  
  28481.  
  28482.  
  28483.  
  28484.  /****************************************************************************
  28485.  * This function gets the file name selected by the user.
  28486.  \****************************************************************************
  28487.  
  28488.  int FAR PASCAL DlgDirSelect(hwnd, lpszIn, idListBox)
  28489.  HWND hwnd;
  28490.  PSZ  lpszIn;
  28491.  int idListBox;
  28492.      {
  28493.      CHAR sz[MAX_FNAME_LEN];
  28494.      int item;
  28495.      PSZ  lpsz, lpszFile;
  28496.      BOOL fDir;
  28497.  
  28498.      /* get currently selected list entry */
  28499.      item = (int) SHORT1FROMMR(WinSendDlgItemMsg(hwnd, idListBox, LM_QUERYSELE
  28500.      if (item == LIT_NONE)
  28501.          return FALSE;
  28502.      WinSendDlgItemMsg(hwnd, idListBox, LM_QUERYITEMTEXT,
  28503.                        MPFROM2SHORT(item, MAX_FNAME_LEN), (MPARAM)(PSZ)sz);
  28504.      lpszFile = sz;
  28505.  
  28506.      /* extract name */
  28507.      if (fDir = (*sz == '['))
  28508.          {
  28509.          lpszFile = NextChar(lpszFile);
  28510.          if (*lpszFile == '-')
  28511.              {
  28512.              /* drive selection */
  28513.              lpszFile = NextChar(lpszFile);
  28514.              *(lpszFile+1) = ':';
  28515.              *(lpszFile+2) = '\0';
  28516.              }
  28517.          else
  28518.              {
  28519.              /* directory selection */
  28520.              lpsz = lpszFile;
  28521.              while (*lpsz != ']')
  28522.                  lpsz = NextChar(lpsz);
  28523.              *lpsz = '\\';
  28524.              }
  28525.          }
  28526.  
  28527.      lstrcpy(lpszIn, lpszFile);
  28528.      return (fDir);
  28529.      }
  28530.  
  28531.  
  28532.  
  28533.  
  28534.  /****************************************************************************
  28535.  * This function tries to open pdlf=>szFileName.  If the file does not
  28536.  * exist, the function asks to create it.
  28537.  *
  28538.  *  Returns:
  28539.  *    TDF_NOOPEN  - Illegal Filename or user didn't want to create
  28540.  *    TDF_OLDOPEN - Existing file
  28541.  *    TDF_NEWOPEN - File was created
  28542.  \****************************************************************************
  28543.  
  28544.  USHORT PASCAL DlgOpenFile(pdlf, hwnd)
  28545.  PDLF pdlf;
  28546.  HWND hwnd;
  28547.      {
  28548.      /* check for legal dos name */
  28549.      if (!DlgParseFile((PSZ)pdlf->szFileName, (PSZ)pdlf->szOpenFile,
  28550.                        FALSE, FALSE))
  28551.          {
  28552.          DlgAlertBox(hwnd, IDS_IFN, pdlf, MB_OK | MB_ICONEXCLAMATION);
  28553.          return (TDF_NOOPEN);
  28554.          }
  28555.      /* see if file already exists */
  28556.      if (DlgParseFile((PSZ)pdlf->szFileName, (PSZ)pdlf->szOpenFile,
  28557.                        TRUE, FALSE))
  28558.          {
  28559.          if (OpenFile((PSZ)pdlf->szFileName, pdlf->phFile,
  28560.                          (PSZ)pdlf->szOpenFile, OF_READ))
  28561.              return (TDF_OLDOPEN);
  28562.          else
  28563.              {
  28564.              DlgAlertBox(hwnd, IDS_EOF, pdlf, MB_OK | MB_ICONEXCLAMATION);
  28565.              return (TDF_NOOPEN);
  28566.              }
  28567.          }
  28568.      /* file doesn't exist: create new one? */
  28569.      else if (DlgAlertBox(hwnd, IDS_FNF, pdlf, MB_YESNO | MB_ICONQUESTION) ==
  28570.          {
  28571.          if (OpenFile((PSZ)pdlf->szFileName, pdlf->phFile,
  28572.                          (PSZ)pdlf->szOpenFile, OF_CREATE))
  28573.              return (TDF_NEWOPEN);
  28574.          else
  28575.              DlgAlertBox(hwnd, IDS_ECF, pdlf, MB_OK | MB_ICONEXCLAMATION);
  28576.          }
  28577.      return(TDF_NOOPEN);
  28578.      }
  28579.  
  28580.  
  28581.  
  28582.  
  28583.  /****************************************************************************
  28584.  * This function returns the OS/2 file handle if operation is successful,
  28585.  * 0 otherwise.
  28586.  *
  28587.  * Effects:  Depend on wMode:
  28588.  *     OF_READ:      open file for reading only
  28589.  *     OF_WRITE:     open file for writing only
  28590.  *     OF_READWRITE: open file for reading and writing
  28591.  *     OF_CREATE:    create the file if it does not exist
  28592.  *     OF_REOPEN:    open file using info in the reopen buffer
  28593.  *     OF_EXIST:     test file existence
  28594.  *     OF_PARSE:     fill reopen buffer, with no other action
  28595.  \****************************************************************************
  28596.  
  28597.  
  28598.  BOOL EXPENTRY OpenFile(lpszFile, lpHandle, lpszOpenFile, wMode)
  28599.  PSZ  lpszFile;
  28600.  PHFILE lpHandle;
  28601.  PSZ  lpszOpenFile;
  28602.  USHORT wMode;
  28603.      {
  28604.      HFILE hFile = NULL;
  28605.      USHORT wAction = NULL;
  28606.      USHORT wAttrs = NULL;
  28607.      USHORT wOpenFlag, wOpenMode;
  28608.      CHAR sz[MAX_FNAME_LEN];
  28609.  
  28610.      /* if reopen specified, use earlier pathname */
  28611.      if (wMode & OF_REOPEN)
  28612.          {
  28613.          lstrcpy((PSZ)sz, lpszOpenFile);
  28614.          lpszFile = (PSZ)sz;
  28615.          }
  28616.  
  28617.      /* parse file */
  28618.      if (!DlgParseFile(lpszFile, lpszOpenFile, wMode&OF_EXIST, FALSE))
  28619.          {
  28620.          *lpszOpenFile = '\0';
  28621.          return FALSE;
  28622.          }
  28623.      /* return if implementing boolean test OF_PARSE or OF_EXIST */
  28624.      if (wMode & (OF_PARSE | OF_EXIST))
  28625.          {
  28626.          return TRUE;
  28627.          }
  28628.  
  28629.      if (wMode & OF_READ)
  28630.          {
  28631.          wOpenFlag = 0x01;               /* fail if it doesn't exist */
  28632.          wOpenMode = 0x20;               /* read only */
  28633.          }
  28634.      else if (wMode & OF_WRITE)
  28635.          {
  28636.          wOpenFlag = 0x11;               /* create if necessary */
  28637.          wOpenMode = 0x11;               /* write only */
  28638.          }
  28639.      else if (wMode & OF_READWRITE)
  28640.          {
  28641.          wOpenFlag = 0x11;               /* create if necessary */
  28642.          wOpenMode = 0x12;               /* read-write */
  28643.          }
  28644.      else if (wMode & OF_CREATE)
  28645.          {
  28646.          /* create and close file */
  28647.          wOpenFlag = 0x10;               /* fail if exists */
  28648.          wOpenMode = 0x10;               /* read only */
  28649.          }
  28650.      else
  28651.          {
  28652.          return FALSE;
  28653.          }
  28654.  
  28655.      if (DosOpen(lpszFile, (PHFILE)&hFile, &wAction,
  28656.                  (ULONG) 0, 0, wOpenFlag, wOpenMode, (ULONG) 0))
  28657.          return FALSE;
  28658.  
  28659.      if (wMode & OF_CREATE)
  28660.          {
  28661.          if (DosClose(hFile))
  28662.              return FALSE;
  28663.          }
  28664.      else
  28665.          *lpHandle = hFile;
  28666.  
  28667.      return TRUE;
  28668.      }
  28669.  
  28670.  
  28671.  
  28672.  
  28673.  /****************************************************************************
  28674.  * This function puts a path string into a static box.
  28675.  \****************************************************************************
  28676.  
  28677.  PSZ  PASCAL DlgFitPathToBox(hwnd, idStatic, lpch)
  28678.  HWND hwnd;
  28679.  int idStatic;
  28680.  PSZ  lpch;
  28681.      {
  28682.      WRECT rc;
  28683.      int cxField;
  28684.      char chDrive;
  28685.      HPS hps;
  28686.  
  28687.      /* get length of static field */
  28688.      WinQueryWindowRect(WinWindowFromID(hwnd, idStatic), (PRECTL)&rc);
  28689.      cxField = rc.xRight - rc.xLeft;
  28690.  
  28691.      hps = WinGetPS(hwnd);
  28692.      if (cxField < (int) LOUSHORT(GetTextExtent(hps, lpch,
  28693.                                             lstrlen(lpch))))
  28694.          {
  28695.          chDrive = *lpch;
  28696.          /* chop characters off front of string until text is short enough */
  28697.          do
  28698.              do
  28699.                  lpch = NextChar(lpch);
  28700.              while (*(lpch+6) != '\\' &&
  28701.                     *(lpch+6) != '\0');
  28702.          while (cxField < (int) LOUSHORT(GetTextExtent(hps, lpch,
  28703.                                                   lstrlen(lpch))));
  28704.          /* insert header */
  28705.          *lpch++ = chDrive;
  28706.          *lpch++ = ':';
  28707.          *lpch++ = '\\';
  28708.          *lpch++ = '.';
  28709.          *lpch++ = '.';
  28710.          *lpch++ = '.';
  28711.          lpch -= 6;
  28712.          }
  28713.      WinReleasePS(hps);
  28714.      return (lpch);
  28715.      }
  28716.  
  28717.  
  28718.  
  28719.  
  28720.  /****************************************************************************
  28721.  * This function fills a list box with appropriate file names from the
  28722.  * current directory.
  28723.  \****************************************************************************
  28724.  
  28725.  int PASCAL DlgFillListBoxes(hwnd, idDirList, idFileList, attr, lpszFileSpec)
  28726.  HWND   hwnd;
  28727.  int    idDirList;
  28728.  int    idFileList;
  28729.  USHORT attr;
  28730.  PSZ    lpszFileSpec;
  28731.      {
  28732.      USHORT usFiles, usDrive;
  28733.      int i;
  28734.      PSZ  lpsz;
  28735.      HDIR hDir;
  28736.      ULONG lrgfDrives;
  28737.      FILEFINDBUF ffb;
  28738.      CHAR sz[20];
  28739.      int cDrives;
  28740.      int result = -1;
  28741.      HWND hwndFiles, hwndDirs;
  28742.  
  28743.      /* get listbox window handles */
  28744.      hwndFiles = WinWindowFromID(hwnd, idFileList);
  28745.      hwndDirs = WinWindowFromID(hwnd, idDirList);
  28746.  
  28747.      /* disable updates to listboxes */
  28748.      WinEnableWindowUpdate(hwndFiles, FALSE);
  28749.      WinEnableWindowUpdate(hwndDirs, FALSE);
  28750.  
  28751.      /* empty list boxes of any old entries */
  28752.      WinSendMsg(hwndFiles, LM_DELETEALL, 0L, 0L);
  28753.      WinSendMsg(hwndDirs, LM_DELETEALL, 0L, 0L);
  28754.  
  28755.      /* put files that lMatch search spec in file listbox */
  28756.      usFiles = 1;
  28757.      hDir = 0xFFFF;
  28758.      if (!DosFindFirst(lpszFileSpec, (PHDIR)&hDir,
  28759.          attr&~(BITATTRDIR|BITATTRDRIVE), (PFILEFINDBUF)&ffb, sizeof(FILEFINDB
  28760.          &usFiles, 0L))
  28761.          {
  28762.          do
  28763.              {
  28764.              /* add string to list box */
  28765.              result = (int) SHORT1FROMMR(WinSendMsg(hwndFiles, LM_INSERTITEM,
  28766.                                        MPFROM2SHORT(LIT_SORTASCENDING, 0),
  28767.                                        (MPARAM)(PSZ)&(ffb.achName[0])));
  28768.              usFiles = 1;
  28769.              }
  28770.          while (result >= 0 && !DosFindNext(hDir,
  28771.                                             (PFILEFINDBUF)&ffb,
  28772.                                             sizeof(FILEFINDBUF),
  28773.                                             &usFiles));
  28774.          DosFindClose(hDir);
  28775.          }
  28776.  
  28777.      if (result != LIT_MEMERROR && (attr   & BITATTRDIR))
  28778.          {
  28779.          /* get directories */
  28780.          usFiles = 1;
  28781.          hDir = 0xFFFF;
  28782.          if (!DosFindFirst((PSZ)szStarStar, (PHDIR)&hDir, BITATTRDIR,
  28783.              (PFILEFINDBUF)&ffb, sizeof(FILEFINDBUF), &usFiles, 0l))
  28784.              {
  28785.              do
  28786.                  {
  28787.                  /* extract file name */
  28788.                  if (ffb.attrFile & BITATTRDIR)
  28789.                      {
  28790.                      /* put brackets around directory */
  28791.                      lpsz = (PSZ)&(ffb.achName[0]);
  28792.                      if (*lpsz == '.' && *(lpsz+1) == '\0')
  28793.                          /* forget about current directory name '.' */
  28794.                          continue;
  28795.                      sz[0] = '[';
  28796.                      lstrcpy((PSZ)&sz[1], lpsz);
  28797.                      sz[ffb.cchName    + 1] = ']';
  28798.                      sz[ffb.cchName    + 2] = '\0';
  28799.                      lpsz = (PSZ)sz;
  28800.                      /* add string to list box */
  28801.                      result = (int) SHORT1FROMMR(WinSendMsg(hwndDirs, LM_INSER
  28802.                                                MPFROM2SHORT(LIT_SORTASCENDING,
  28803.                                                (MPARAM)lpsz));
  28804.                      }
  28805.                  usFiles = 1;
  28806.                  }
  28807.              while (result >= -1 && !DosFindNext(hDir,
  28808.                                                 (PFILEFINDBUF)&ffb,
  28809.                                                 sizeof(FILEFINDBUF),
  28810.                                                 &usFiles));
  28811.              DosFindClose(hDir);
  28812.              }
  28813.          }
  28814.  
  28815.      if (result != LIT_MEMERROR && (attr   & BITATTRDRIVE))
  28816.          /* get drives */
  28817.          {
  28818.          sz[0] = '[';
  28819.          sz[1] = sz[3] = '-';
  28820.          sz[4] = ']';
  28821.          sz[5] = '\0';
  28822.  
  28823.          DosQCurDisk(&usDrive, (unsigned long far *)&lrgfDrives);
  28824.          cDrives = 0;
  28825.          for (i=0; 'A' + i <= 'Z'; i++)
  28826.              {
  28827.              if (lrgfDrives & 1L)
  28828.                  {
  28829.                  sz[2] = (char)('A' + i);
  28830.                  /* add drive to list */
  28831.                  result = (int) SHORT1FROMMR(WinSendMsg(hwndDirs, LM_INSERTITE
  28832.                                            MPFROM2SHORT(LIT_END, 0),
  28833.                                            (MPARAM)(PSZ)sz));
  28834.                  cDrives++;
  28835.                  }
  28836.              lrgfDrives >>= 1;
  28837.              }
  28838.          }
  28839.  
  28840.      /* enable and show updated listboxes */
  28841.      WinShowWindow(hwndFiles, TRUE);
  28842.      WinShowWindow(hwndDirs, TRUE);
  28843.  
  28844.      return result;
  28845.      }
  28846.  
  28847.  
  28848.  
  28849.  
  28850.  /****************************************************************************
  28851.  * This function parses a string into an fully expanded file name or search
  28852.  * path.  If fExist is true then the file must exist or the search path must
  28853.  * correspond to at least one existing file.  In all cases, the corresponding
  28854.  * directory must exist.  The string must be a file name, ie. no wildcards,
  28855.  * unless fWildOkay is true.  Returns TRUE if string is parsed correctly.
  28856.  \****************************************************************************
  28857.  
  28858.  BOOL PASCAL DlgParseFile(lpszIn, lpszExp, fExist, fWildOkay)
  28859.  PSZ  lpszIn, lpszExp;
  28860.  BOOL fExist, fWildOkay;
  28861.      {
  28862.      CHAR szPath[MAX_FNAME_LEN];
  28863.      PSZ  lpszFile, lpsz;
  28864.  
  28865.      /* go past any path spec to first char in file name */
  28866.      lpszFile = FileInPath(lpszIn);
  28867.  
  28868.      /* check validity of file name */
  28869.      if (!fExist && !DlgValidName(lpszFile, fWildOkay))
  28870.          {
  28871.          *lpszExp = '\0';
  28872.          return FALSE;
  28873.          }
  28874.  
  28875.      /* copy path part to path string */
  28876.      lpsz = (PSZ)szPath;
  28877.      if (lpszIn == lpszFile)
  28878.          *lpsz++ = '.';
  28879.      else
  28880.          {
  28881.          while (lpszIn < lpszFile && lpsz < ((PSZ)szPath + MAX_FNAME_LEN - 1))
  28882.              *lpsz++ = *lpszIn++;
  28883.          }
  28884.      *lpsz = '\0';
  28885.  
  28886.      /* let DOS do the dirty work */
  28887.      if (fExist)
  28888.          {
  28889.          /* test existence of file while parsing path */
  28890.          if (DosSearchPath(0, (PSZ)szPath, lpszFile, lpszExp, MAX_FNAME_LEN))
  28891.              {
  28892.              *lpszExp = '\0';
  28893.              return FALSE;
  28894.              }
  28895.          }
  28896.      else
  28897.          {
  28898.          /* use dummy wild card while parsing path */
  28899.          if (DosSearchPath(0, (PSZ)szPath, (PSZ)szStarStar, lpszExp, MAX_FNAME
  28900.              {
  28901.              *lpszExp = '\0';
  28902.              return FALSE;
  28903.              }
  28904.          /* replace wild card part with true file name converted to CAPS */
  28905.          lpsz = lpszExp;
  28906.          while (*lpsz != '?' && *lpsz != '*' && *lpsz != '\0')
  28907.              lpsz++;
  28908.          while (*lpszFile != '\0')
  28909.              {
  28910.              *lpsz++ = *lpszFile++;
  28911.              }
  28912.          *lpsz = '\0';
  28913.          Upper(lpszExp);
  28914.          }
  28915.      return TRUE;
  28916.      }
  28917.  
  28918.  
  28919.  
  28920.  
  28921.  /****************************************************************************
  28922.  * This function determines if a string forms a legal file name or search
  28923.  * path.  Wildcard characters are acceptable if fWildOkay is true.  Returns
  28924.  * TRUE if string is legal.
  28925.  \****************************************************************************
  28926.  
  28927.  BOOL PASCAL DlgValidName(lpszName, fWildOkay)
  28928.  PSZ  lpszName;
  28929.  BOOL fWildOkay;
  28930.      {
  28931.      int cLen;
  28932.      PSZ  lpsz;
  28933.  
  28934.      /* check file name */
  28935.      if (*lpszName == '\0')
  28936.          return FALSE;
  28937.      cLen = 0;
  28938.      lpsz = lpszName;
  28939.      while (*lpsz != '\0' && *lpsz != '.')
  28940.          {
  28941.          if (++cLen > 8 || *lpsz < 0x20)
  28942.              return FALSE;
  28943.          switch (*lpsz++)
  28944.              {
  28945.              case '*':
  28946.              case '?':
  28947.                  if (fWildOkay)
  28948.                      break;
  28949.              case '\"':
  28950.              case '\\':
  28951.              case '/':
  28952.              case '[':
  28953.              case ']':
  28954.              case ':':
  28955.              case '|':
  28956.              case '<':
  28957.              case '>':
  28958.              case '+':
  28959.              case '=':
  28960.              case ';':
  28961.              case ',':
  28962.                  return FALSE;
  28963.              }
  28964.          }
  28965.  
  28966.      /* check extension */
  28967.      if (*lpsz++ == '\0')
  28968.          return TRUE;
  28969.      cLen = 0;
  28970.      while (*lpsz != '\0')
  28971.          {
  28972.          if (++cLen > 3 || *lpsz < 0x20)
  28973.              return FALSE;
  28974.          switch (*lpsz++)
  28975.              {
  28976.              case '*':
  28977.              case '?':
  28978.                  if (fWildOkay)
  28979.                      break;
  28980.              case '.':
  28981.              case '\"':
  28982.              case '\\':
  28983.              case '/':
  28984.              case '[':
  28985.              case ']':
  28986.              case ':':
  28987.              case '|':
  28988.              case '<':
  28989.              case '>':
  28990.              case '+':
  28991.              case '=':
  28992.              case ';':
  28993.              case ',':
  28994.                  return FALSE;
  28995.              }
  28996.          }
  28997.      return TRUE;
  28998.      }
  28999.  
  29000.  
  29001.  GPI.C
  29002.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\OPENDLG\GPI.C
  29003.  
  29004.  /***************************************************************************\
  29005.  * GPI.C -- GPI Helper routines
  29006.  * Created by Microsoft Corporation, 1989
  29007.  \***************************************************************************/
  29008.  
  29009.  
  29010.  #define INCL_GPI
  29011.  #include "tool.h"
  29012.  
  29013.  /***************************************************************************\
  29014.  * GetTextExtent helper function
  29015.  \***************************************************************************/
  29016.  
  29017.  ULONG EXPENTRY GetTextExtent(HPS hps, PCH lpstr, int cch) {
  29018.      POINTL rgptl[TXTBOX_COUNT];
  29019.  
  29020.      if (cch) {
  29021.          GpiQueryTextBox(hps, (LONG)cch, lpstr, 5L, rgptl);
  29022.          return(MAKEULONG((SHORT)(rgptl[TXTBOX_CONCAT].x - rgptl[TXTBOX_BOTTOM
  29023.                       (SHORT)(rgptl[TXTBOX_TOPLEFT].y - rgptl[TXTBOX_BOTTOMLEF
  29024.      } else
  29025.          return(0L);
  29026.      }
  29027.  
  29028.  
  29029.  HANOI.C
  29030.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\HANOI\HANOI.C
  29031.  
  29032.  /*************************************************************
  29033.  
  29034.   This program implements a tower of hanoi program.  This
  29035.   sample app was written to demonstrate the use of a multi-
  29036.   threaded program.  The main thread handles the PM interface,
  29037.   the second thread is started to do the recursive execution
  29038.   of the hanoi algorithm.
  29039.  
  29040.   This program was written by Jeff Johnson, 7/89.
  29041.  
  29042.   Procedures in this file:
  29043.     main()             Sets up the PM environment and heap and
  29044.                        calls the main window procedure ClientWndProc
  29045.     ClientWndProc()    Handles the main window messages
  29046.     CalcThread()       Sets up and terminates the secondary thread
  29047.     DrawDisk()         Draws or erases a disk on one of the poles
  29048.     MoveDisk()         Moves a disk from one pole to another
  29049.     Hanoi()            Recursive alogrithm for tower of hanoi prog
  29050.     EnableMenuItem()   Activates/deactivates a menu choice
  29051.     EntryFldDlgProc()  Handles the set number of disks dialog box
  29052.     SetupTowers()      Sets up the global tower data
  29053.  
  29054.  **************************************************************/
  29055.  
  29056.  #include "hanoi.h"
  29057.  
  29058.  
  29059.  /********************* GLOBALS *******************************/
  29060.  
  29061.  CHAR szClientClass[] = "Hanoi";
  29062.  
  29063.  /* Note that this use of global data precludes multiple windows
  29064.     of hanoi running at the same time.  Thus, from an object-
  29065.     oriented perspective, this is less than desireable and the
  29066.     data should be passed into the window, rather than used
  29067.     explicitly. */
  29068.  
  29069.  BYTE abTowers[3][MAXDISKCNT];     /* Used to hold disk numbers on each post *
  29070.  BYTE abTowersNdx[3];              /* Current number of disks on each post   *
  29071.  BYTE cTowerSize = DEFAULTSIZE;   /* Holds the total number of disks        */
  29072.  USHORT ausPolePos[3]= { POSTOFFSET, /* Holds offset drawing information     *
  29073.                         POSTOFFSET + POSTSPACE,
  29074.                         POSTOFFSET + 2*POSTSPACE };
  29075.  ULONG  ulIterations;
  29076.  
  29077.  /*************************************************************/
  29078.  
  29079.  
  29080.  /*
  29081.   * Function name: main()
  29082.   *
  29083.   * Parameters:  argc, argv.  If the user places a number (1 thru MAXDISKCNT)
  29084.   *              on the command line, that number will become the default
  29085.   *              number of disks on the stack. Otherwise there will be
  29086.   *              DEFUALTSIZE disks initially.
  29087.   *
  29088.   * Returns: Always returns 0
  29089.   *
  29090.   * Purpose: Parses the command line, sets up the PM environment, prepares
  29091.   *          the Tower arrays, calls the main window proc, handles the
  29092.   *          window's messages then cleans up and exits.
  29093.   *
  29094.   * Usage/Warnings:
  29095.   *
  29096.   * Calls: ClientWndProc() (thru PM)
  29097.   */
  29098.  
  29099.  int main(int argc, char *argv[])
  29100.  {
  29101.     HAB          hab;
  29102.     HMQ          hmq;
  29103.     HWND         hwndFrame, hwndClient;
  29104.     QMSG         qmsg;
  29105.  
  29106.     ULONG flFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU | FCF_MINBUTTON |
  29107.                          FCF_SHELLPOSITION | FCF_MENU    | FCF_TASKLIST  |
  29108.                          FCF_ICON          | FCF_BORDER  | FCF_ACCELTABLE;
  29109.  
  29110.     SHORT sHold;
  29111.  
  29112.     if(argc > 1)  /* If command line arg, use as the initial number of disks *
  29113.     {
  29114.        sHold = atoi(argv[1]);
  29115.        if(sHold>0 && sHold<=MAXDISKCNT)
  29116.           cTowerSize = (BYTE) sHold;
  29117.     }
  29118.     SetupTowers();
  29119.  
  29120.     /* These PM calls should be error checked */
  29121.     hab = WinInitialize(0);
  29122.     hmq = WinCreateMsgQueue(hab, 0);
  29123.  
  29124.     if(!WinRegisterClass(hab, szClientClass,ClientWndProc,0L,0))
  29125.     {
  29126.        WinAlarm(HWND_DESKTOP, WA_ERROR);        /* Register failed */
  29127.        DosExit(EXIT_PROCESS,1);
  29128.     }
  29129.  
  29130.     hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
  29131.                                    &flFrameFlags, szClientClass, NULL,
  29132.                                    0L, (HMODULE) NULL, ID_MAINMENU, &hwndClien
  29133.     if(!hwndFrame)
  29134.     {
  29135.        WinAlarm(HWND_DESKTOP, WA_ERROR); /* Window create failed */
  29136.        DosExit(EXIT_PROCESS,1);
  29137.     }
  29138.  
  29139.     while(WinGetMsg(hab,&qmsg,NULL,0,0))        /* Message loop */
  29140.        WinDispatchMsg(hab,&qmsg);
  29141.  
  29142.     WinDestroyWindow(hwndFrame);                /* Clean up     */
  29143.     WinDestroyMsgQueue(hmq);
  29144.     WinTerminate(hab);
  29145.     return 0;
  29146.  }
  29147.  
  29148.  
  29149.  /*
  29150.   * Function name: ClientWndProc()
  29151.   *
  29152.   * Parameters:  hwnd, msg, mp1, mp2.  Standard PM Window Proc params.
  29153.   *              No user data is expected in the WM_CREATE.
  29154.   *
  29155.   * Returns:
  29156.   *
  29157.   * Purpose: Handles all the messages associated with the main window
  29158.   *          and calls the appropriate handling procedures.
  29159.   *
  29160.   * Usage/Warnings: Called only by main().  Note that when WM_PAINT executes,
  29161.   *                 the secondary thread may change data during the update
  29162.   *                 which may cause a problem.  However, this is NOT a write
  29163.   *                 conflict, as only 1 thread does the writing.
  29164.   *
  29165.   * Calls:  DrawDisk(), CalcThread() (thru Thread), EntryFldDlgProc() (thru PM
  29166.   */
  29167.  
  29168.  MRESULT EXPENTRY ClientWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  29169.  {
  29170.     HPS    hps;                         /* Handle for painting           */
  29171.     RECTL  rcl;                         /* Rectangle struct for painting */
  29172.     POINTL ptl;                         /* Point struct for painting     */
  29173.     BYTE   cPole,bCnt,bHeight,cnt;      /* Utility variables             */
  29174.     CHAR   szMsg[MSGBUFSIZE];           /* sprintf buffer                */
  29175.     static CALCPARAM cp;                /* Struct used to notify thread  */
  29176.     static TID    tidCalc;              /* Secondary thread ID           */
  29177.     static VOID   *pThreadStack;        /* Pointer to secondary stack    */
  29178.  
  29179.     switch(msg)
  29180.     {
  29181.        case WM_PAINT:
  29182.           hps = WinBeginPaint(hwnd,NULL,NULL);   /* Get paint handle     */
  29183.           WinQueryWindowRect(hwnd,&rcl);
  29184.  
  29185.           DrawRect(rcl.xLeft,rcl.yBottom,        /* White out the screen */
  29186.                    rcl.xRight,rcl.yTop,CLR_WHITE);
  29187.  
  29188.           /* Draw the base */
  29189.           DrawRect(BASEXOFFSET,           BASEYOFFSET,
  29190.                    BASEXOFFSET+BASELEN-1, BASEYOFFSET+BASETHICK-1,
  29191.                    CLR_DARKGREEN);
  29192.  
  29193.           /* Draw the 3 posts */
  29194.           bHeight = (BYTE) (cTowerSize*DISKSPACE + POSTEXTRAHT);
  29195.           for(cnt=0;cnt<3;cnt++)
  29196.           {
  29197.              DrawRect(ausPolePos[cnt]-POSTHALF,          BASEYOFFSET,
  29198.                       ausPolePos[cnt]-POSTHALF+POSTWIDTH,bHeight,
  29199.                       CLR_DARKGREEN);
  29200.           }
  29201.  
  29202.           /* Place the appropriate disks on each pole */
  29203.           for(cPole=0;cPole<3;cPole++)
  29204.           {
  29205.              for(bCnt=0;bCnt<abTowersNdx[cPole];bCnt++)
  29206.              {
  29207.                 DrawDisk(hps,cPole,bCnt,fDRAW);
  29208.              }
  29209.           }
  29210.  
  29211.           WinEndPaint(hps);
  29212.           return 0L;
  29213.  
  29214.        case WM_COMMAND:
  29215.           switch(COMMANDMSG(&msg)->cmd)
  29216.           {
  29217.              case IDM_START:
  29218.                 /* Try to get stack space */
  29219.                 if((pThreadStack = malloc(STACKSIZE)) == NULL)
  29220.                 {
  29221.                    WinAlarm(HWND_DESKTOP, WA_ERROR);  /* Couldn't get memory *
  29222.                    return 0L;
  29223.                 }
  29224.                 cp.hwnd = hwnd;           /* Set the static struct  */
  29225.                 cp.fContinueCalc = TRUE;
  29226.                 ulIterations = 0;         /* Zero iteration counter */
  29227.  
  29228.                 /* Try to start the thread */
  29229.                 if((tidCalc = _beginthread(CalcThread,pThreadStack,
  29230.                                            STACKSIZE, &cp))     == -1)
  29231.                 {
  29232.                    free(pThreadStack);    /* Thread wouldn't start  */
  29233.                    WinAlarm(HWND_DESKTOP, WA_ERROR);
  29234.                    return 0L;
  29235.                 }
  29236.                 /* Disallow menu items that could change data while the second
  29237.                    thread is running */
  29238.                 EnableMenuItem(hwnd,IDM_START,FALSE); /* Disable Start & set *
  29239.                 EnableMenuItem(hwnd,IDM_SET,FALSE);
  29240.                 EnableMenuItem(hwnd,IDM_STOP,TRUE);   /* Enable Stop item    *
  29241.                 return 0L;
  29242.  
  29243.              case IDM_STOP:
  29244.                 cp.fContinueCalc = FALSE;  /* Notify thread to quit          *
  29245.                 return 0L;
  29246.  
  29247.              case IDM_SET:
  29248.                 if(WinDlgBox(HWND_DESKTOP, hwnd, /* Pop up the query/set box *
  29249.                           EntryFldDlgProc,(HMODULE) NULL,ID_SETCOUNT,NULL))
  29250.                 {
  29251.                    SetupTowers();                          /* Reset towers   *
  29252.                    WinInvalidateRect(hwnd,NULL,FALSE);     /* Force a redraw *
  29253.                 }
  29254.                 return 0L;
  29255.  
  29256.               default:
  29257.                  return WinDefWindowProc(hwnd, msg, mp1, mp2);
  29258.           }
  29259.  
  29260.        case UM_CALC_DONE:
  29261.           EnableMenuItem(hwnd,IDM_START,TRUE);  /* Reenable Start & set      *
  29262.           EnableMenuItem(hwnd,IDM_SET,TRUE);
  29263.           EnableMenuItem(hwnd,IDM_STOP,FALSE);  /* Disable stop              *
  29264.           free(pThreadStack);                   /* Free thread's stack space *
  29265.  
  29266.           sprintf(szMsg,"%lu disks were moved.",ulIterations);  /* Print msg *
  29267.           WinMessageBox(HWND_DESKTOP, hwnd, szMsg, "Done!", 0, MB_OK);
  29268.  
  29269.           SetupTowers();                        /* Reset towers              *
  29270.           WinInvalidateRect(hwnd,NULL,FALSE);   /* Force a screen redraw     *
  29271.           return 0L;
  29272.  
  29273.         default:
  29274.            return WinDefWindowProc(hwnd, msg, mp1, mp2);
  29275.     }
  29276.  }
  29277.  
  29278.  
  29279.  /*
  29280.   * Function name: CalcThread()
  29281.   *
  29282.   * Parameters:  pcp is a struct which contains the hwnd handle and the
  29283.   *              continue flag which is initially set to TRUE.
  29284.   *
  29285.   * Returns: VOID
  29286.   *
  29287.   * Purpose: Calls the recursive Hanoi with initial setting of 0,2,1 meaning
  29288.   *          from pole 0, to pole 2, using pole 1 as a temporary.  Hanoi
  29289.   *          returns when finished, or the user says stop.  This proc then
  29290.   *          sets a critical section so the posted message won't be handled
  29291.   *          until the thread is terminated.
  29292.   *
  29293.   * Usage/Warnings: No DosExitCritSec() is called since _endthread() supposedl
  29294.   *                 clears the critical section when the thread is
  29295.   *                 terminated.
  29296.   *
  29297.   * Calls:  Hanoi()
  29298.   */
  29299.  
  29300.  VOID _cdecl FAR CalcThread(PCALCPARAM pcp)
  29301.  {
  29302.     HAB hab;
  29303.  
  29304.     hab = WinInitialize(0);    /* Called to increase Ring 2 stack size */
  29305.     Hanoi(pcp,cTowerSize,0,2,1);      /* Execute the recursive routine */
  29306.     WinTerminate(hab);
  29307.  
  29308.     DosEnterCritSec(); /* Set Crit so the UM_CALC_DONE isn't processed */
  29309.                        /* until this thread has completely terminated  */
  29310.     WinPostMsg(pcp->hwnd,UM_CALC_DONE,NULL,NULL);         /* Post done */
  29311.  
  29312.     _endthread();                                  /* Terminate thread */
  29313.  }
  29314.  
  29315.  
  29316.  /*
  29317.   * Function name: DrawDisk()
  29318.   *
  29319.   * Parameters:  hps is a handle to the main PS space.
  29320.   *              cPole is the pole (0-2) to draw the disk on.
  29321.   *              bLevel is the number of spaces from the bottom to draw disk.
  29322.   *              fDraw if =0, erase disk, if =1 draw disk.
  29323.   *
  29324.   * Returns: VOID
  29325.   *
  29326.   * Purpose: This routine takes a PS handle, the hanoi spindle and disk level
  29327.   *          and draws an appropriately sized disk.
  29328.   *
  29329.   * Usage/Warnings: Does not grab exclusive access to the screen before
  29330.   *                 drawing which may cause a problem.
  29331.   *
  29332.   * Calls:
  29333.   */
  29334.  
  29335.  VOID DrawDisk(HPS hps,BYTE cPole, BYTE bLevel,BYTE fDraw)
  29336.  {
  29337.     USHORT usXstart,usYstart,usWidth;
  29338.     POINTL ptl;
  29339.  
  29340.     usYstart = BOTDISKYPOS + DISKSPACE*bLevel;  /* Calculate Bottom of disk
  29341.  
  29342.     usWidth  = (MAXDISKWIDTH-MINDISKWIDTH)*abTowers[cPole][bLevel]/cTowerSize
  29343.                + MINDISKWIDTH;                  /* Calculate the disk's width
  29344.  
  29345.     usXstart = ausPolePos[cPole] - usWidth/2;   /* Center disk on pole
  29346.  
  29347.     if(fDraw == fDRAW)  /* If we are to draw the disk */
  29348.     {
  29349.        DrawRect(usXstart,usYstart,usXstart+usWidth,
  29350.                 usYstart+DISKTHICK-1,CLR_RED);
  29351.     }
  29352.     else         /* We are to erase the disk, then redraw the pole */
  29353.     {
  29354.        DrawRect(usXstart,usYstart,usXstart+usWidth,
  29355.                 usYstart+DISKTHICK-1,CLR_WHITE);
  29356.        DrawRect(ausPolePos[cPole]-POSTHALF,usYstart,
  29357.                 ausPolePos[cPole]-POSTHALF+POSTWIDTH,usYstart+DISKTHICK-1,
  29358.                 CLR_DARKGREEN);
  29359.     }
  29360.  }
  29361.  
  29362.  
  29363.  /*
  29364.   * Function name: MoveDisk()
  29365.   *
  29366.   * Parameters:  hps is a handle to the main PS space.
  29367.   *              bFrom is the spindle to take the top disk from.
  29368.   *              bTo is the spindle to place the disk on.
  29369.   *
  29370.   * Returns: VOID
  29371.   *
  29372.   * Purpose: This routine moves the top disk from the bFrom spindle to the top
  29373.   *          of the bTo spindle.
  29374.   *
  29375.   * Usage/Warnings: Does error checking for trying to move a disk from a
  29376.   *                 spindle that does not have any disks on it.
  29377.   *
  29378.   * Calls:  MoveDisk()
  29379.   */
  29380.  
  29381.  VOID MoveDisk(HPS hps,BYTE bFrom,BYTE bTo)
  29382.  {
  29383.     CHAR bTOSndx;  /* Top of stack index  */
  29384.     BYTE bDiskNum; /* Disk number to move */
  29385.  
  29386.     bTOSndx = (CHAR) (abTowersNdx[bFrom]-1);
  29387.     if(bTOSndx < 0)
  29388.        return;
  29389.  
  29390.     DrawDisk(hps,bFrom,bTOSndx,fERASE);   /* Remove disk off from stack     */
  29391.  
  29392.     bDiskNum = abTowers[bFrom][bTOSndx];  /* Get move disk number           */
  29393.     abTowersNdx[bFrom]--;                 /* Decrease count on from spindle */
  29394.  
  29395.     bTOSndx = abTowersNdx[bTo]++;         /* Offset to place the disk at    */
  29396.     abTowers[bTo][bTOSndx] = bDiskNum;    /* Place on stack in memory       */
  29397.  
  29398.     DrawDisk(hps,bTo,bTOSndx,fDRAW);      /* Draw disk on the to stack      */
  29399.  }
  29400.  
  29401.  
  29402.  /*
  29403.   * Function name: Hanoi()
  29404.   *
  29405.   * Parameters:  pcp is a struct which contains the hwnd handle and the
  29406.   *                  continue flag which is initially set to TRUE.
  29407.   *              bHeight is the number of disks in the from stack to move.
  29408.   *              bFrom is the from spindle number, 0-2.
  29409.   *              bTo is the to spindle number.
  29410.   *              bTemp is the temporary spindle number.
  29411.   *
  29412.   * Returns: VOID
  29413.   *
  29414.   * Purpose: This routine implements a recursive hanoi program that works as
  29415.   *          follows:  By recursion, move all the disks, except for the
  29416.   *          bottom disk to the temporary stack.  Then move the bottom
  29417.   *          disk to the target spindle.  Now recursively move the stack
  29418.   *          on the temporary spindle to the target spindle.  The limiting
  29419.   *          case is when Hanoi() is called with a bHeight of 0 in which
  29420.   *          case the depth recursion is terminated.
  29421.   *
  29422.   * Usage/Warnings: This routine checks the ->fContinueCalc flag, which is set
  29423.   *                 by the main thread when the user selects stop, to see if
  29424.   *                 the user wishes to abort the algorithm.  If so, it backs
  29425.   *                 out and exits.
  29426.   *
  29427.   * Calls:  MoveDisk()
  29428.   */
  29429.  
  29430.  VOID Hanoi(PCALCPARAM pcp, BYTE bHeight, BYTE bFrom, BYTE bTo, BYTE bTemp)
  29431.  {
  29432.     HPS hps;
  29433.  
  29434.     if(bHeight<=0 || !pcp->fContinueCalc)  /* Exit up if no more disks or */
  29435.        return;                             /* the user said Stop          */
  29436.  
  29437.     Hanoi(pcp,(BYTE)(bHeight-1),bFrom,bTemp,bTo);  /* Move all but bottom disk
  29438.  
  29439.     if(!pcp->fContinueCalc)                /* If user said to stop        */
  29440.        return;
  29441.  
  29442.     /* Display bFrom -> bTo */
  29443.     hps = WinGetPS(pcp->hwnd);
  29444.     MoveDisk(hps,bFrom,bTo);               /* Move the bottom disk        */
  29445.     WinReleasePS(hps);
  29446.     ulIterations++;
  29447.  
  29448.     Hanoi(pcp,(BYTE)(bHeight-1),bTemp,bTo,bFrom);  /* Move disks over
  29449.  }
  29450.  
  29451.  
  29452.  /*
  29453.   * Function name: EnableMenuItem()
  29454.   *
  29455.   * Parameters:  hwnd is a handle of the current window.
  29456.   *              sMenuItem is the ID of the item to Enable/Disable.
  29457.   *              fEnable will enable item if TRUE, otherwise disables it.
  29458.   *
  29459.   * Returns: VOID
  29460.   *
  29461.   * Purpose: This routine handles enabling/disabling of menu items.  This
  29462.   *          is done by getting Parent and Menu hwnd handles then sending
  29463.   *          the appropriate message.
  29464.   *
  29465.   * Usage/Warnings:
  29466.   *
  29467.   * Calls:
  29468.   */
  29469.  
  29470.  VOID EnableMenuItem(HWND hwnd, SHORT sMenuItem, BOOL fEnable)
  29471.  {
  29472.     HWND hwndParent = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  29473.     HWND hwndMenu   = WinWindowFromID(hwndParent, FID_MENU);
  29474.  
  29475.     WinSendMsg(hwndMenu, MM_SETITEMATTR,
  29476.                MPFROM2SHORT(sMenuItem, TRUE),
  29477.                MPFROM2SHORT(MIA_DISABLED, fEnable ? 0 : MIA_DISABLED));
  29478.  }
  29479.  
  29480.  
  29481.  /*
  29482.   * Function name: EntryFldDlgProc()
  29483.   *
  29484.   * Parameters:  hwnd, msg, mp1, mp2.  Standard PM Dialog Proc params.
  29485.   *              No user data is expected in the WM_CREATE.
  29486.   *
  29487.   * Returns: Terminates with a TRUE iff a new valid Tower Size has been entere
  29488.   *
  29489.   * Purpose: Handles all the messages associated with the set entry field
  29490.   *          and calls the appropriate handling procedures.  The purpose
  29491.   *          of this dialog box is to get a new number of disks for the
  29492.   *          hanoi routine.
  29493.   *
  29494.   *
  29495.   * Usage/Warnings: If the value entered is valid, global cTowerSize is
  29496.   *                 changed to the new value, and TRUE is returned.
  29497.   *
  29498.   * Calls:
  29499.   */
  29500.  
  29501.  MRESULT EXPENTRY EntryFldDlgProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp
  29502.  {
  29503.     SHORT sNewSize;            /* Holds new number of disks        */
  29504.  
  29505.     switch(msg)
  29506.     {
  29507.        case WM_INITDLG:
  29508.           WinSendDlgItemMsg(hwnd, ID_ENTRYFLD,EM_SETTEXTLIMIT,  /* Limit len *
  29509.                                   MPFROM2SHORT(2,0),NULL);
  29510.           WinSetDlgItemShort(hwnd, ID_ENTRYFLD,(SHORT) cTowerSize,TRUE);
  29511.           return 0L;                           /* Allow normal focus setting *
  29512.  
  29513.        case WM_COMMAND:
  29514.           switch(COMMANDMSG(&msg)->cmd)
  29515.           {
  29516.              case DID_OK:
  29517.                 WinQueryDlgItemShort(hwnd, ID_ENTRYFLD,
  29518.                                      &sNewSize, TRUE); /* Get the short      *
  29519.                 if(sNewSize>0 && sNewSize<=MAXDISKCNT) /* Set new Tower size *
  29520.                 {
  29521.                    cTowerSize = (BYTE) sNewSize;
  29522.                    WinDismissDlg(hwnd,TRUE);
  29523.                 }
  29524.                 else                                   /* Invalid value      *
  29525.                    WinDismissDlg(hwnd,FALSE);
  29526.                 return 0L;
  29527.  
  29528.              case DID_CANCEL:
  29529.                 WinDismissDlg(hwnd,FALSE);
  29530.                 return 0L;
  29531.  
  29532.              default:
  29533.                 return WinDefDlgProc(hwnd, msg, mp1, mp2);
  29534.           }
  29535.  
  29536.        default:
  29537.           return WinDefDlgProc(hwnd, msg, mp1, mp2);
  29538.     }
  29539.  }
  29540.  
  29541.  /*
  29542.   * Function name: SetupTowers()
  29543.   *
  29544.   * Parameters:  None
  29545.   *
  29546.   * Returns: VOID
  29547.   *
  29548.   * Purpose: This routine initializes the global arrays that represent the
  29549.   *          hanoi stacks.  This involves placing all the disks on the
  29550.   *          first peg, emptying the other 2 pegs and setting the associated
  29551.   *          counts.
  29552.   *
  29553.   * Usage/Warnings: Calling uses the global variable cTowerSize to determine
  29554.   *                 how many disks there are.
  29555.   *
  29556.   * Calls:
  29557.   */
  29558.  
  29559.  VOID SetupTowers()
  29560.  {
  29561.     USHORT cnt;
  29562.  
  29563.     for(cnt=0;cnt<cTowerSize;cnt++)       /* Setup the intial post with disks
  29564.        abTowers[0][cnt] = (BYTE)(cTowerSize-cnt-1);
  29565.  
  29566.     abTowersNdx[0] = cTowerSize;          /* Set disk count for initial post
  29567.     abTowersNdx[1] = abTowersNdx[2] = 0;  /* Zero other post counts
  29568.  }
  29569.  
  29570.  
  29571.  
  29572.  HELLO.C
  29573.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\OPENDLG\HELLO\HELLO.C
  29574.  
  29575.  /*
  29576.   * HELLO.C -- A simple program which calls the OpenDlg library
  29577.   * Created by Microsoft Corporation, 1989
  29578.   */
  29579.  #define INCL_PM
  29580.  #include <os2.h>
  29581.  #include <opendlg.h>
  29582.  #include "hello.h"
  29583.  /*
  29584.   * Globals
  29585.   */
  29586.  HAB     hAB;
  29587.  HMQ     hMqHello;
  29588.  HWND    hWndHello;
  29589.  HWND    hWndHelloFrame;
  29590.  CHAR    szClassName[]        = "Hello World";
  29591.  CHAR        szMessage[]        = " - File Dialog Sample";
  29592.  CHAR        szExtension[]        = "\\*.*";
  29593.  CHAR        szHelp[]        = "Help would go here.";
  29594.  DLF        vdlf;
  29595.  HFILE        vhFile;
  29596.  /*
  29597.   * Main routine...initializes window and message queue
  29598.   */
  29599.  int cdecl main( ) {
  29600.      QMSG qmsg;
  29601.      ULONG ctldata;
  29602.  
  29603.      hAB = WinInitialize(0);
  29604.  
  29605.      hMqHello = WinCreateMsgQueue(hAB, 0);
  29606.  
  29607.      if (!WinRegisterClass( hAB, (PCH)szClassName, (PFNWP)HelloWndProc,
  29608.                  CS_SIZEREDRAW, 0))
  29609.          return( 0 );
  29610.  
  29611.      /* Create the window */
  29612.      ctldata = FCF_STANDARD & ~(FCF_ACCELTABLE);
  29613.      hWndHelloFrame = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE, &ctldata,
  29614.                                           szClassName, szMessage,
  29615.                                           WS_VISIBLE, (HMODULE) NULL, ID_RESOU
  29616.                                           (HWND FAR *)&hWndHello );
  29617.  
  29618.      WinShowWindow( hWndHelloFrame, TRUE );
  29619.  
  29620.      /* Poll messages from event queue */
  29621.      while( WinGetMsg( hAB, (PQMSG)&qmsg, (HWND)NULL, 0, 0 ) )
  29622.          WinDispatchMsg( hAB, (PQMSG)&qmsg );
  29623.  
  29624.      /* Clean up */
  29625.      WinDestroyWindow( hWndHelloFrame );
  29626.      WinDestroyMsgQueue( hMqHello );
  29627.      WinTerminate( hAB );
  29628.  }
  29629.  
  29630.  MRESULT CALLBACK HelloWndProc(hWnd, msg, mp1, mp2)
  29631.  /*
  29632.   * This routine processes WM_COMMAND, WM_PAINT.  It passes
  29633.   * everything else to the Default Window Procedure.
  29634.   */
  29635.  HWND hWnd;
  29636.  USHORT msg;
  29637.  MPARAM mp1;
  29638.  MPARAM mp2;
  29639.  {
  29640.      HPS                hPS;
  29641.      POINTL        pt;
  29642.      CHARBUNDLE        cb;
  29643.      RECTL        rcl;
  29644.  
  29645.      switch (msg) {
  29646.  
  29647.          case WM_COMMAND:
  29648.              switch (COMMANDMSG(&msg)->cmd) {
  29649.  
  29650.                  case IDM_OPEN: /* Demonstrate Open... dialog call */
  29651.                      SetupDLF( &vdlf
  29652.                              , DLG_OPENDLG
  29653.                              , &vhFile
  29654.                              , szExtension
  29655.                              , NULL
  29656.                              , "Open Title"
  29657.                              , szHelp );
  29658.                       DlgFile(hWndHelloFrame, &vdlf);
  29659.                      break;
  29660.  
  29661.                  case IDM_SAVE: /* Demonstrate Save As... dialog call */
  29662.                      SetupDLF( &vdlf
  29663.                              , DLG_SAVEDLG
  29664.                              , &vhFile
  29665.                              , szExtension
  29666.                              , NULL
  29667.                              , "Save Title"
  29668.                              , szHelp);
  29669.                      lstrcpy( (PSZ)vdlf.szOpenFile, (PSZ)"foo.bar");
  29670.                      DlgFile(hWndHelloFrame, &vdlf);
  29671.                      break;
  29672.  
  29673.                  case IDM_ABOUT:
  29674.                      WinDlgBox(HWND_DESKTOP, hWnd, AboutDlgProc,
  29675.                                (HMODULE) NULL, IDD_ABOUT, NULL);
  29676.                      return 0;
  29677.  
  29678.                  default: break;
  29679.              }
  29680.              break;
  29681.  
  29682.          case WM_PAINT:
  29683.              /* Open the presentation space */
  29684.              hPS = WinBeginPaint(hWnd, NULL, &rcl);
  29685.  
  29686.              /* Fill the background with Dark Blue */
  29687.              WinFillRect(hPS, &rcl, CLR_DARKBLUE);
  29688.  
  29689.              /* Write "Hello World" in Red */
  29690.              pt.x = pt.y = 0L;
  29691.              cb.lColor = CLR_RED;
  29692.              GpiSetAttrs(hPS, PRIM_CHAR, CBB_COLOR, 0L, &cb);
  29693.              GpiCharStringAt(hPS, &pt, (LONG)sizeof(szClassName)-1, szClassNam
  29694.  
  29695.              /* Finish painting */
  29696.              WinEndPaint(hPS);
  29697.              break;
  29698.  
  29699.          default: return WinDefWindowProc(hWnd, msg, mp1, mp2); break;
  29700.      }
  29701.      return 0L;
  29702.  }
  29703.  
  29704.  MRESULT CALLBACK AboutDlgProc(hDlg, msg, mp1, mp2)
  29705.  /*
  29706.      About... dialog procedure
  29707.  */
  29708.  HWND hDlg;
  29709.  USHORT msg;
  29710.  MPARAM mp1;
  29711.  MPARAM mp2;
  29712.  {
  29713.      switch(msg) {
  29714.          case WM_COMMAND:
  29715.              switch(COMMANDMSG(&msg)->cmd) {
  29716.                  case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  29717.                  default: break;
  29718.              }
  29719.          default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  29720.      }
  29721.      return FALSE;
  29722.  }
  29723.  
  29724.  
  29725.  INIEDIT.C
  29726.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\INIEDIT\INIEDIT.C
  29727.  
  29728.  /******************************* Module Header ******************************
  29729.  * Module Name: IniEdit.c
  29730.  *
  29731.  *
  29732.  * PM OS2.ini Editor
  29733.  *
  29734.  * Allows adding, deleting and modifying of os2.ini entries through PM
  29735.  * interface
  29736.  *
  29737.  *
  29738.  \***************************************************************************/
  29739.  
  29740.  
  29741.  #define LINT_ARGS                           // Include needed parts of PM
  29742.  #define INCL_WININPUT                       //    definitions
  29743.  #define INCL_WINSYS
  29744.  #define INCL_WINMESSAGEMGR
  29745.  #define INCL_WINBUTTONS
  29746.  #define INCL_WINPOINTERS
  29747.  #define INCL_WINHEAP
  29748.  #define INCL_WINSHELLDATA
  29749.  #define INCL_WINMENUS
  29750.  #define INCL_WINFRAMEMGR
  29751.  #define INCL_WINDIALOGS
  29752.  #define INCL_WINLISTBOXES
  29753.  #define INCL_WINENTRYFIELDS
  29754.  #define INCL_DOSMEMMGR
  29755.  #define INCL_WINSWITCHLIST
  29756.  #define INCL_DOSPROCESS
  29757.  #define INCL_GPIBITMAPS
  29758.  #define INCL_GPIREGIONS
  29759.  #define INCL_GPILCIDS
  29760.  #define INCL_GPIPRIMITIVES
  29761.  #define INCL_DEV
  29762.  
  29763.  #include <string.h>
  29764.  #include <stdio.h>
  29765.  
  29766.  #include <os2.h>
  29767.  
  29768.  #include "IniEdit.h"
  29769.  
  29770.  
  29771.  /******************************* Constants **********************************
  29772.  
  29773.  #define STACK_SIZE            0x2000        // Stack size for second thread
  29774.  #define UPPER_SEGMENT_LIMIT   0xFD00        // Amount of Segment used
  29775.  
  29776.  /******************************** Globals **********************************/
  29777.  
  29778.  char szIniEdit[] = "IniEdit";               // App String Name
  29779.  
  29780.  HAB       habIniEdit;                       // Handle Anchor Block
  29781.  HMQ       hmqIniEdit;                       // Handle Message Queue
  29782.  HWND      hwndIniEdit;                      // Main Client Window
  29783.  HWND      hwndIniEditFrame;                 // Frame Window
  29784.  HDC       hdcScreen;                        // DC for Client Window
  29785.  HPS       hpsScreen;                        // PS for Client Window
  29786.  
  29787.  
  29788.  USHORT    cAppNames = 0;                    // Count of App names in os2.ini
  29789.  USHORT    usShift = 0;                      // DosHugeAlloc segment offsets
  29790.  HWND      FocusWindow = (HWND)NULL;         // Focus of Dialog Box
  29791.  USHORT    cxBorder;                         // System border width
  29792.  USHORT    cyBorder;                         // System border height
  29793.  
  29794.  USHORT    usFormat = APP_FORM;              // Current Display format
  29795.  USHORT    usPrintFormat = APP_FORM;         // Format for Printing
  29796.  USHORT    usLineHeight = 12;                // Current font Height
  29797.  HWND      hwndList = (HWND)NULL;            // Handle of Main ListBox
  29798.  HWND      hwndMenu = (HWND)NULL;            // Handle of Main Menu
  29799.  
  29800.  PGROUPSTRUCT  pGroups;                      // Pointer to String Groups
  29801.  PPAIRSTRUCT   pPairsBase;                   // Pointer to Key-Value Pairs
  29802.  PPAIRSTRUCT   pPairsAlloc;                  // Pointer to next Avail Memory
  29803.  PBYTE         pPrintStack;                  // Pointer to Print Thread Stack
  29804.  
  29805.  #define HOLD_LEN 4096
  29806.  CHAR          achNames[HOLD_LEN];           // Array of Character from Query
  29807.  CHAR          szBuf[2 * MAX_STRING_LEN];        // Character buffer for Pairs
  29808.  
  29809.  
  29810.  /***************************** Function Decls ******************************/
  29811.  
  29812.  VOID    ProcessMenuItem( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 );
  29813.  VOID    cdecl main( VOID );
  29814.  VOID    IniEditPaint( VOID );
  29815.  VOID    ReadIni( VOID );
  29816.  VOID    OldProfilePrint( VOID );
  29817.  VOID    UpdateListBox( BOOL fRead, USHORT usForm );
  29818.  
  29819.  MRESULT _loadds EXPENTRY IniEditWndProc(HWND, USHORT, MPARAM, MPARAM);
  29820.  
  29821.  
  29822.  /***************************** Function Header *****************************\
  29823.  *
  29824.  * main
  29825.  *
  29826.  *
  29827.  * Do initialization then do a message loop
  29828.  *
  29829.  \***************************************************************************/
  29830.  
  29831.  VOID cdecl main()
  29832.  {
  29833.  
  29834.      QMSG         qmsg;                      // Current Queue Message
  29835.      ULONG        fcf;                       // Frame Control Flags
  29836.      SIZEL        sizel;                     // Size of PS
  29837.      RECTL        rclWindow;                 // Size Rect for ListBox Window
  29838.      SEL          sel;                       // Selector of allocated segments
  29839.      SWCNTRL      swcntrl;                   // Switch Control Block
  29840.      FONTMETRICS  fmetrics;                  // FontMetrics of current font
  29841.  
  29842.  
  29843.      /*** Set up and Initialization ***/
  29844.  
  29845.      /* Initialize the anchor block handle */
  29846.      habIniEdit = WinInitialize(0);
  29847.  
  29848.      /* Create the message queue */
  29849.      hmqIniEdit = WinCreateMsgQueue(habIniEdit, 0);
  29850.  
  29851.      /* Register the window class for the IniEdit window */
  29852.      WinRegisterClass(habIniEdit, (PCH)szIniEdit, IniEditWndProc,
  29853.              CS_SIZEREDRAW, 0);
  29854.  
  29855.      /* Create the window for IniEdit */
  29856.      fcf = FCF_TITLEBAR | FCF_MINMAX | FCF_SYSMENU | FCF_SIZEBORDER | FCF_MENU
  29857.          | FCF_SHELLPOSITION | FCF_ACCELTABLE | FCF_ICON;
  29858.  
  29859.      hwndIniEditFrame = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE,
  29860.          (PVOID)&fcf, (PSZ)szIniEdit, (PSZ)szIniEdit, WS_VISIBLE,
  29861.          (HMODULE)NULL, IDI_INIEDIT, (PHWND)&hwndIniEdit);
  29862.  
  29863.      /* Create a DC for the IniEdit window */
  29864.      hdcScreen = WinOpenWindowDC(hwndIniEdit);
  29865.  
  29866.      /* also create a screen PS */
  29867.  
  29868.      sizel.cx= 0L;   // To use the default screen page size.
  29869.      sizel.cy= 0L;
  29870.  
  29871.      if( (hpsScreen = GpiCreatePS( habIniEdit, hdcScreen, &sizel,
  29872.              (PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC ))) == (HPS)NUL
  29873.          {
  29874.                  ;
  29875.          }
  29876.  
  29877.  
  29878.      /* Initially set the keyboard focus to us */
  29879.      WinSetFocus(HWND_DESKTOP, hwndIniEdit);
  29880.  
  29881.      /* get the font size */
  29882.      GpiQueryFontMetrics( hpsScreen, (LONG)sizeof( FONTMETRICS ), &fmetrics );
  29883.      usLineHeight = (USHORT)(fmetrics.lMaxDescender + fmetrics.lMaxBaselineExt
  29884.  
  29885.      /* get the system widths of a border */
  29886.      cxBorder = (USHORT) WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  29887.      cyBorder = (USHORT) WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
  29888.  
  29889.      /* this menu handle is often used */
  29890.      hwndMenu = WinWindowFromID( hwndIniEditFrame, FID_MENU );
  29891.  
  29892.      /* add program to switch list */
  29893.      swcntrl.hwnd             = hwndIniEditFrame;
  29894.      swcntrl.hwndIcon         = NULL;
  29895.      swcntrl.hprog            = NULL;
  29896.      swcntrl.idProcess        = 0;
  29897.      swcntrl.idSession        = 0;
  29898.      swcntrl.uchVisibility    = 0;
  29899.      swcntrl.fbJump           = 0;
  29900.      strcpy( swcntrl.szSwtitle, szIniEdit);
  29901.      swcntrl.fReserved        = 0;
  29902.  
  29903.      WinAddSwitchEntry( &swcntrl );
  29904.  
  29905.      /* Create main list box in main window */
  29906.      WinQueryWindowRect( hwndIniEdit, &rclWindow);
  29907.      rclWindow.yTop -= usLineHeight;
  29908.      rclWindow.yTop += cyBorder;
  29909.      rclWindow.xRight += 2*cxBorder;
  29910.      hwndList = WinCreateWindow( hwndIniEdit,            // parent
  29911.                                  WC_LISTBOX,             // class
  29912.                                  (PSZ)"Scroll",          // name
  29913.                                  LS_NOADJUSTPOS,         // style
  29914.                                  -cxBorder, -cyBorder,   // position
  29915.                                  (USHORT)rclWindow.xRight,
  29916.                                  (USHORT)rclWindow.yTop,
  29917.                                  hwndIniEditFrame,       // Owner
  29918.                                  HWND_TOP,               // InsertBehind
  29919.                                  IDI_LIST,               // ID
  29920.                                  (PVOID)NULL,            // pCtlData,
  29921.                                  (PVOID)NULL);
  29922.  
  29923.  
  29924.      /*** Memory Allocation ***/
  29925.  
  29926.      /* Alloc the needed space for the groups */
  29927.      if( DosAllocSeg( 32000, &sel, 0) )
  29928.          ErrMessage( "main: DosAlloc for pGroup failed" );
  29929.      pGroups = MAKEP( sel, 0);
  29930.  
  29931.      if( DosAllocHuge( 4, 0, &sel, 0, 0) )
  29932.          ErrMessage( "main: DosAlloc for pPairs failed" );
  29933.      pPairsAlloc = pPairsBase = MAKEP( sel, 0);
  29934.  
  29935.      /* create a stack for second thread */
  29936.      if( DosAllocSeg( STACK_SIZE, &sel, 0) )
  29937.          ErrMessage( "main: DosAlloc for Stack failed" );
  29938.      pPrintStack = MAKEP( sel, 0);
  29939.  
  29940.      DosGetHugeShift( &usShift );
  29941.  
  29942.      /* read in os2.ini and fill in list box */
  29943.      UpdateListBox( TRUE, APP_FORM );
  29944.  
  29945.      WinShowWindow( hwndList, TRUE );
  29946.  
  29947.      /* Process messages for the window */
  29948.      while ( WinGetMsg(habIniEdit, (PQMSG)&qmsg, (HWND)NULL, 0, 0 ) )
  29949.          {
  29950.  
  29951.          /* Dispatch the message */
  29952.          WinDispatchMsg(habIniEdit, (PQMSG)&qmsg);
  29953.          }
  29954.  
  29955.  
  29956.      /*** CleanUp ***/
  29957.  
  29958.      /* Destroy the IniEdit window and message queue */
  29959.      GpiDestroyPS( hpsScreen );
  29960.      WinDestroyWindow(hwndIniEditFrame);
  29961.      WinDestroyMsgQueue(hmqIniEdit);
  29962.  
  29963.      /* Exit PM */
  29964.      WinTerminate( habIniEdit );
  29965.      DosExit( EXIT_PROCESS, 0 );
  29966.  
  29967.  }  /* main */
  29968.  
  29969.  
  29970.  /****************************** Function Header ****************************\
  29971.  *
  29972.  * ReadIni
  29973.  *
  29974.  *
  29975.  * Reads in OS2.ini
  29976.  *
  29977.  \***************************************************************************/
  29978.  
  29979.  VOID ReadIni()
  29980.  {
  29981.      USHORT    cchNames;                     // Count of Character from Query
  29982.      USHORT    Index[MAX_APP_NAMES];         // Index of Names into achNames
  29983.      USHORT    cPairs;                       // Count of pairs in current AppN
  29984.      ULONG     ul;
  29985.      USHORT    i,j;                          // Loop Counters
  29986.  
  29987.  
  29988.      /* Reset Count of App Names */
  29989.      cAppNames = 0;
  29990.  
  29991.      /* Reset memory available pointer to Base */
  29992.      pPairsAlloc = pPairsBase;
  29993.  
  29994.      /* Determine number of characters in app Names Strings */
  29995.      WinQueryProfileSize( habIniEdit, NULL, NULL, &cchNames );
  29996.  
  29997.      /* Read in the App Name strings */
  29998.      WinQueryProfileString( habIniEdit, NULL, NULL, " ", achNames, cchNames );
  29999.  
  30000.      /*** Find the starting index of each App ***/
  30001.  
  30002.      /* step through each string in set of app characters
  30003.       * adding length of current string to find begining of next string
  30004.       * also store each App Name into szAppName element of Group
  30005.       */
  30006.      for( i=0; i<cchNames; i += (strlen(pGroups[cAppNames-1].szAppName)+1) )
  30007.          {
  30008.          if( achNames[i] != (char)0 )
  30009.              {
  30010.              strcpy( pGroups[cAppNames++].szAppName, &achNames[i]);
  30011.              }  /* if */
  30012.          else
  30013.              if( achNames[i+1] == (char)0 )
  30014.                  break;
  30015.          }  /* for */
  30016.  
  30017.  
  30018.      /*** Read elements of each App Name ***/
  30019.      for( i=0; i<cAppNames; i++ )
  30020.          {
  30021.          /* Get number of Character Associated with App Name */
  30022.          WinQueryProfileSize( habIniEdit, pGroups[i].szAppName, NULL, &cchName
  30023.  
  30024.          /* Enumerate all KeyNames for this app name */
  30025.          WinQueryProfileString( habIniEdit, pGroups[i].szAppName, NULL, " ", a
  30026.  
  30027.          /* Count the number of key Names */
  30028.          cPairs = 0;
  30029.          for( j=0; j<cchNames; j++)
  30030.              if( achNames[j] != (CHAR)0 )
  30031.                  {
  30032.                  Index[cPairs++] = j;
  30033.                  j += strlen( &achNames[j] );
  30034.                  }
  30035.  
  30036.          pGroups[i].cKeys = cPairs;
  30037.  
  30038.          /*
  30039.           * Make sure we can fit the entire structure into our current
  30040.           * segment, if not, lets jump to the next segment
  30041.           */
  30042.          ul =  sizeof(PAIRSTRUCT) * cPairs;
  30043.          if ((ul + (ULONG)OFFSETOF(pPairsAlloc)) >= 0x10000L)
  30044.              pPairsAlloc = MAKEP( (HIUSHORT(pPairsAlloc)+(1<<usShift)), 0);
  30045.  
  30046.  
  30047.  
  30048.          /* Allocate the number of pair structures for the current group */
  30049.          pGroups[i].pPairs = pPairsAlloc;
  30050.  
  30051.          // pPairsAlloc += sizeof(PAIRSTRUCT)*cPairs;
  30052.          // Remember that incrementing a pointer automatically mult by size of
  30053.          pPairsAlloc += cPairs;
  30054.  
  30055.          /* Step to next segment if near end of current segment */
  30056.          if( LOUSHORT(pPairsAlloc) > UPPER_SEGMENT_LIMIT)
  30057.              {
  30058.              pPairsAlloc = MAKEP( (HIUSHORT(pPairsAlloc)+(1<<usShift)), 0);
  30059.              }
  30060.  
  30061.          /* Store the KeyName into the pair structure */
  30062.          for( j=0; j<cPairs; j++ )
  30063.              {
  30064.              strcpy( pGroups[i].pPairs[j].szKey, &achNames[Index[j]] );
  30065.  
  30066.              /* store the key value */
  30067.              WinQueryProfileString( habIniEdit, pGroups[i].szAppName,
  30068.                       pGroups[i].pPairs[j].szKey, " ",
  30069.                       pGroups[i].pPairs[j].szValue, MAX_STRING_LEN );
  30070.  
  30071.              }
  30072.          }  /* each App Name */
  30073.  
  30074.  }  /* ReadIni */
  30075.  
  30076.  
  30077.  /****************************** Function Header ****************************\
  30078.  *
  30079.  * ProcessMenuItem
  30080.  *
  30081.  *
  30082.  * Act on the corresponding Menu Item Choosen
  30083.  *
  30084.  \***************************************************************************/
  30085.  
  30086.  VOID ProcessMenuItem( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  30087.  {
  30088.      TID  Tid;                               // ID of new thread; Not used
  30089.  
  30090.  
  30091.      /* Switch on the Menu Item choosen */
  30092.      switch( LOUSHORT( mp1 ) )
  30093.          {
  30094.          case IDMI_SHOW_ALL:
  30095.          case IDMI_SHOW_APPNAMES:
  30096.              usFormat = (LOUSHORT(mp1) == IDMI_SHOW_ALL);
  30097.              UpdateListBox( FALSE, usFormat ? ALL_FORM : APP_FORM );
  30098.              break;
  30099.  
  30100.          case IDM_SEARCH:
  30101.              WinDlgBox(HWND_DESKTOP, hwndIniEditFrame, (PFNWP)SearchWndProc,
  30102.                              (HMODULE)NULL, IDD_SEARCH, (PVOID)NULL);
  30103.              break;
  30104.  
  30105.          case IDMI_EDIT_DELETE_KEY:
  30106.              WinDlgBox(HWND_DESKTOP, hwndIniEditFrame, (PFNWP)DelKeyWndProc,
  30107.                              (HMODULE)NULL, IDD_DEL_KEY, (PVOID)NULL);
  30108.              UpdateListBox( TRUE, usFormat ? ALL_FORM : APP_FORM );
  30109.              break;
  30110.  
  30111.          case IDMI_EDIT_DELETE_APP:
  30112.              WinDlgBox(HWND_DESKTOP, hwndIniEditFrame, (PFNWP)DelAppWndProc,
  30113.                              (HMODULE)NULL, IDD_DEL_APP, (PVOID)NULL);
  30114.              UpdateListBox( TRUE, usFormat ? ALL_FORM : APP_FORM );
  30115.              break;
  30116.  
  30117.          case IDMI_EDIT_ADD_KEY:
  30118.              WinDlgBox(HWND_DESKTOP, hwndIniEditFrame, (PFNWP)AddKeyWndProc,
  30119.                              (HMODULE)NULL, IDD_ADD_KEY, (PVOID)NULL);
  30120.              UpdateListBox( TRUE, usFormat ? ALL_FORM : APP_FORM );
  30121.              break;
  30122.  
  30123.          case IDMI_EDIT_CHANGE:
  30124.              WinDlgBox(HWND_DESKTOP, hwndIniEditFrame, (PFNWP)ChangeKeyWndProc
  30125.                              (HMODULE)NULL, IDD_CHANGE_KEY, (PVOID)NULL);
  30126.              UpdateListBox( TRUE, usFormat ? ALL_FORM : APP_FORM );
  30127.              break;
  30128.  
  30129.          case IDMI_PRINT_ALL:
  30130.          case IDMI_PRINT_APP:
  30131.              usPrintFormat = LOUSHORT(mp1) == IDMI_PRINT_ALL ? ALL_FORM : APP_
  30132.              if( DosCreateThread( PrintThread, &Tid, ((PBYTE)(pPrintStack)+STA
  30133.                  ErrMessage("StartThread2: DosCreateThread Failed");
  30134.              break;
  30135.  
  30136.          case IDMI_REFRESH:
  30137.              UpdateListBox( TRUE, usFormat );
  30138.              break;
  30139.  
  30140.          case IDMI_ABOUT:
  30141.              WinDlgBox(HWND_DESKTOP, hwndIniEditFrame, (PFNWP)DelAppWndProc,
  30142.                              (HMODULE)NULL, IDD_ABOUT, (PVOID)NULL);
  30143.              break;
  30144.  
  30145.          default:
  30146.              WinDefWindowProc(hwnd, msg, mp1, mp2);
  30147.  
  30148.              break;
  30149.  
  30150.          }  /* switch */
  30151.  
  30152.  }  /* ProcessMenuItem */
  30153.  
  30154.  
  30155.  /****************************** Function Header ****************************\
  30156.  *
  30157.  * UpdateListBox
  30158.  *
  30159.  *
  30160.  * Update Main List Box to correct state
  30161.  *    May Also:
  30162.  *    - Check correct menu item
  30163.  *    - Repaint title of List Box
  30164.  *    - ReRead os2.ini file
  30165.  *
  30166.  \***************************************************************************/
  30167.  
  30168.  VOID UpdateListBox( BOOL fReadIni, USHORT usNewFormat )
  30169.  {
  30170.      USHORT    i,j;                          // Loop Counters
  30171.      USHORT    Index;                        // Index into ListBox
  30172.      static    USHORT    usLastFormat = -1;  // Last displayed format
  30173.  
  30174.  
  30175.      /* Check the correct item if format changed */
  30176.      if( usLastFormat != usNewFormat )
  30177.          {
  30178.          WinSendMsg( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(IDMI_SHOW_ALL, TRU
  30179.                  MPFROM2SHORT(MIA_CHECKED, usFormat ? MIA_CHECKED:FALSE));
  30180.  
  30181.          WinSendMsg( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(IDMI_SHOW_APPNAMES
  30182.                  MPFROM2SHORT(MIA_CHECKED, (!usFormat) ? MIA_CHECKED:FALSE));
  30183.          usLastFormat = usNewFormat;
  30184.  
  30185.          WinSendMsg( hwndIniEdit, WM_PAINT, (MPARAM)NULL, (MPARAM)NULL );
  30186.          }
  30187.  
  30188.  
  30189.      /* Turn off list box updates */
  30190.      WinEnableWindowUpdate( hwndList, FALSE );
  30191.  
  30192.      /* Remove all items from list box */
  30193.      WinSendMsg( hwndList, LM_DELETEALL, (MPARAM)0, (MPARAM)0 );
  30194.  
  30195.      /* ReRead os2.ini if needed */
  30196.      if( fReadIni )
  30197.          ReadIni();
  30198.  
  30199.      /* Add elements to listbox */
  30200.      if( usNewFormat == ALL_FORM )
  30201.          {
  30202.  
  30203.          /* Insert all app Names */
  30204.          for( i=0; i<cAppNames; i++ )
  30205.              {
  30206.              Index = SHORT1FROMMR(WinSendMsg( hwndList, LM_INSERTITEM,
  30207.                      MPFROM2SHORT(LIT_END, NULL),
  30208.                      MPFROMP(pGroups[i].szAppName) ));
  30209.  
  30210.              WinSendMsg( hwndList, LM_SETITEMHANDLE,
  30211.                      MPFROMSHORT(Index),
  30212.                      MPFROMSHORT(i) );
  30213.  
  30214.              /* Insert Key Value Pairs for App Name */
  30215.              for( j=0; j<pGroups[i].cKeys; j++ )
  30216.                  {
  30217.                  sprintf( szBuf, "     %s: %s", pGroups[i].pPairs[j].szKey,
  30218.                          pGroups[i].pPairs[j].szValue );
  30219.                  Index = SHORT1FROMMR(WinSendMsg( hwndList, LM_INSERTITEM,
  30220.                          MPFROM2SHORT(LIT_END, NULL),
  30221.                          MPFROMP(szBuf) ));
  30222.  
  30223.                  WinSendMsg( hwndList, LM_SETITEMHANDLE,
  30224.                          MPFROMSHORT(Index),
  30225.                          MPFROM2SHORT(i,j) );
  30226.  
  30227.                  }
  30228.              }
  30229.          }  /* if */
  30230.      else
  30231.          {
  30232.          /* Insert all app Names */
  30233.          for( i=0; i<cAppNames; i++ )
  30234.              {
  30235.              WinSendMsg( hwndList, LM_INSERTITEM,
  30236.                      MPFROM2SHORT(LIT_SORTASCENDING, NULL),
  30237.                      MPFROMP(pGroups[i].szAppName) );
  30238.              }
  30239.          }  /* else */
  30240.  
  30241.      /* Do All repainting of ListBox */
  30242.      WinEnableWindowUpdate( hwndList, TRUE );
  30243.  
  30244.  }  /* UpdateListBox */
  30245.  
  30246.  
  30247.  /****************************** Function Header ****************************\
  30248.  *
  30249.  * IniEditPaint
  30250.  *
  30251.  *
  30252.  * Window Paint Routine
  30253.  *
  30254.  \***************************************************************************/
  30255.  
  30256.  VOID IniEditPaint()
  30257.  {
  30258.      RECTL     rclWindow;                    // Current size of Main Window
  30259.      RECTL     rclBlit;                      // Size of Area to Blank for Titl
  30260.      CHAR      szShowMode[MAX_STRING_LEN];   // String Description of mode
  30261.  
  30262.  
  30263.      /* Get the size of the whole window */
  30264.      WinQueryWindowRect( hwndIniEdit, &rclWindow );
  30265.  
  30266.      /* Paint the window Title Area */
  30267.      rclBlit = rclWindow;
  30268.      rclBlit.yBottom = rclBlit.yTop - usLineHeight;
  30269.  
  30270.      GpiBitBlt( hpsScreen, (HPS)NULL, 2L, (PPOINTL)&rclBlit, ROP_ONE, (LONG)NU
  30271.  
  30272.      /* Write the Title */
  30273.      strcpy( szShowMode, usFormat == APP_FORM ? SZAPP : SZALL );
  30274.      WinDrawText( hpsScreen, strlen(szShowMode), szShowMode, &rclWindow,
  30275.              CLR_BLUE, CLR_WHITE, DT_CENTER|DT_TOP);
  30276.  
  30277.  }  /* IniEditPaint */
  30278.  
  30279.  
  30280.  /****************************** Function Header ****************************\
  30281.  *
  30282.  * IniEditWndProc
  30283.  *
  30284.  *
  30285.  * Window Proc for IniEdit
  30286.  *
  30287.  \***************************************************************************/
  30288.  
  30289.  MRESULT _loadds EXPENTRY IniEditWndProc(HWND hwnd, USHORT msg,
  30290.          MPARAM mp1, MPARAM mp2)
  30291.  {
  30292.  
  30293.      CHAR      szBuf[MAX_STRING_LEN];        // Input character Buffer
  30294.      CHAR      szBuf2[MAX_STRING_LEN];       // Second Input Character Buffer
  30295.      USHORT    Index;                        // Index of Current ListBox Item
  30296.      USHORT    TopIndex;                     // Current Top Item in ListBox
  30297.      ULONG     Handle;                       // ListBox Item Handle Info
  30298.      HWND      hwndDialog;                   // Window handle of Dailog Box
  30299.      HWND      hwndText;                     // Handle of current text window
  30300.      HPS       hpsPaint;                     // PS to Paint
  30301.      RECTL     rclPaint;                     // Rect in hpsPaint to Paint
  30302.      BOOL      fScroll = FALSE;              // Scroll List Box Flag
  30303.  
  30304.  
  30305.      /* Switch on message being processed */
  30306.      switch( msg )
  30307.          {
  30308.          case WM_PAINT:
  30309.              /* Paint the IniEdit window portion not covered by List Box */
  30310.              hpsPaint = WinBeginPaint(hwnd, (HPS)NULL, &rclPaint);
  30311.              IniEditPaint();
  30312.              WinEndPaint(hpsPaint);
  30313.              break;
  30314.  
  30315.          case WM_COMMAND:
  30316.              /* If menu item call Processing Routine */
  30317.              if( LOUSHORT( mp2 ) == CMDSRC_MENU )
  30318.                  ProcessMenuItem( hwnd, msg, mp1, mp2 );
  30319.  
  30320.              /* If accelorator call appropriate routine */
  30321.              if( LOUSHORT( mp2 ) == CMDSRC_ACCELERATOR )
  30322.                  {
  30323.                  switch( LOUSHORT( mp1 ) )
  30324.                      {
  30325.                      case IDDI_SEARCH_NEXT:
  30326.                          FindNext();
  30327.                          break;
  30328.                      }
  30329.                  }
  30330.              break;
  30331.  
  30332.          case WM_SIZE:
  30333.              /* Put the list box in the correct location of the window */
  30334.              if( hwndList != (HWND)NULL )
  30335.                  /* The position is set to fill the client, except for the */
  30336.                  /* area at the top for some text.  In addition, the       */
  30337.                  /* rectangle is outset by a border width on all dimensions*/
  30338.                  /* except for the top so that the list box border is      */
  30339.                  /* "tucked" under the clients border and doesn't cause    */
  30340.                  /* there to be a double thick border around it.           */
  30341.                  WinSetWindowPos( hwndList, HWND_TOP, -cxBorder, -cyBorder,
  30342.                          SHORT1FROMMP(mp2)+(2*cxBorder),
  30343.                          SHORT2FROMMP(mp2)-usLineHeight + cyBorder,
  30344.                          SWP_SIZE | SWP_MOVE );
  30345.              break;
  30346.  
  30347.          case WM_CONTROL:
  30348.              /* Switch on Control activated */
  30349.              switch( SHORT1FROMMP(mp1) )
  30350.                  {
  30351.  
  30352.                  /*** Process List Box Activity ***/
  30353.                  case IDI_LIST:
  30354.                      /* was it a double click? */
  30355.                      if( SHORT2FROMMP(mp1) == LN_ENTER )
  30356.                          {
  30357.                          /* get the item clicked on */
  30358.                          Index = SHORT1FROMMR(WinSendMsg( hwndList, LM_QUERYSE
  30359.                                  (MPARAM)0, (MPARAM)0 ));
  30360.  
  30361.                          /* grab its text */
  30362.                          WinSendMsg( hwndList, LM_QUERYITEMTEXT,
  30363.                                  MPFROM2SHORT(Index, MAX_STRING_LEN), MPFROMP(
  30364.  
  30365.                          /* if in APP form toggle to ALL form */
  30366.                          if( usFormat == APP_FORM )
  30367.                              {
  30368.                              usFormat = ALL_FORM;
  30369.                              fScroll = TRUE;
  30370.                              }
  30371.                          else
  30372.                              {
  30373.                              /* if an App name was choosen then go to APP form
  30374.                              if( szBuf[0] != ' ')
  30375.                                  {
  30376.                                  usFormat = APP_FORM;
  30377.                                  fScroll = TRUE;
  30378.                                  }
  30379.                              else
  30380.                                  /* A Key Value Pair was double clicked
  30381.                                   * allow editing of key Value
  30382.                                   */
  30383.                                  {
  30384.  
  30385.                                  FocusWindow = (HWND)1;
  30386.  
  30387.                                  hwndDialog = WinLoadDlg( HWND_DESKTOP,
  30388.                                      hwndIniEditFrame, ChangeKeyWndProc,
  30389.                                      (HMODULE)NULL, IDD_CHANGE_KEY, NULL);
  30390.  
  30391.                                  Handle = (ULONG)WinSendMsg( hwndList, LM_QUER
  30392.                                      MPFROMSHORT(Index), (MPARAM)NULL );
  30393.  
  30394.                                  hwndText = WinWindowFromID( hwndDialog, IDDI_
  30395.                                  WinSendMsg(hwndText, EM_SETTEXTLIMIT,
  30396.                                          MPFROMSHORT(MAX_STRING_LEN), 0L);
  30397.                                  WinSetWindowText( hwndText, pGroups[LOUSHORT(
  30398.  
  30399.                                  /* note bug in PMWin GPs if full segment */
  30400.                                  hwndText = WinWindowFromID( hwndDialog, IDDI_
  30401.                                  WinSendMsg(hwndText, EM_SETTEXTLIMIT,
  30402.                                          MPFROMSHORT(MAX_STRING_LEN), 0L);
  30403.                                  strcpy( szBuf2, pGroups[LOUSHORT(Handle)].pPa
  30404.                                  WinSetWindowText( hwndText, szBuf2 );
  30405.  
  30406.                                  hwndText = WinWindowFromID( hwndDialog, IDDI_
  30407.                                  WinSendMsg(hwndText, EM_SETTEXTLIMIT,
  30408.                                          MPFROMSHORT(MAX_STRING_LEN), 0L);
  30409.                                  strcpy( szBuf2, pGroups[LOUSHORT(Handle)].pPa
  30410.                                  WinSetWindowText( hwndText, szBuf2 );
  30411.  
  30412.                                  WinPostMsg( hwndText, EM_SETSEL,
  30413.                                          MPFROM2SHORT(0, strlen(szBuf2)), (MPA
  30414.  
  30415.                                  if( WinProcessDlg( hwndDialog ) == IDDI_CHANG
  30416.                                      {
  30417.                                      TopIndex = SHORT1FROMMR(WinSendMsg( hwndL
  30418.                                           (MPARAM)NULL, (MPARAM)NULL ));
  30419.  
  30420.                                      UpdateListBox( TRUE, usFormat );
  30421.  
  30422.                                      /* scroll to top */
  30423.                                      WinSendMsg( hwndList, LM_SETTOPINDEX,
  30424.                                           MPFROMSHORT(TopIndex), (MPARAM)NULL
  30425.  
  30426.                                      /* make the item selected */
  30427.                                      WinSendMsg( hwndList, LM_SELECTITEM,
  30428.                                              MPFROMSHORT(Index), MPFROMSHORT(T
  30429.  
  30430.                                      /* make selected */
  30431.                                      }
  30432.  
  30433.                                  WinDestroyWindow( hwndDialog );
  30434.                                  }
  30435.                              }
  30436.  
  30437.                          /* Make the double clicked item selected in new form
  30438.                          if( fScroll )
  30439.                              {
  30440.                              /* put in correct form */
  30441.                              UpdateListBox( FALSE, usFormat );
  30442.  
  30443.                              /* get the index of the item clicked on */
  30444.                              Index = SHORT1FROMMR(WinSendMsg( hwndList, LM_SEA
  30445.                                      MPFROM2SHORT(LSS_SUBSTRING, LIT_FIRST),
  30446.                                      MPFROMP(szBuf) ));
  30447.  
  30448.                              /* scroll that item to the top */
  30449.                              WinSendMsg( hwndList, LM_SETTOPINDEX,
  30450.                                      MPFROMSHORT(Index), (MPARAM)NULL );
  30451.  
  30452.                              /* make the item selected */
  30453.                              WinSendMsg( hwndList, LM_SELECTITEM,
  30454.                                      MPFROMSHORT(Index), MPFROMSHORT(TRUE) );
  30455.                              }
  30456.                          }  /* if ENTER */
  30457.                  }
  30458.              break;
  30459.  
  30460.          default:
  30461.              return WinDefWindowProc(hwnd, msg, mp1, mp2);
  30462.              break;
  30463.          }
  30464.  
  30465.      return 0L;
  30466.  
  30467.  }  /* IniEditWndProc */
  30468.  
  30469.  
  30470.  INIT.C
  30471.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\OPENDLG\INIT.C
  30472.  
  30473.  /***************************************************************************\
  30474.  * INIT.C -- Library initialization funcitons
  30475.  * Created by Microsoft Corporation, 1989
  30476.  \***************************************************************************/
  30477.  
  30478.  #include "tool.h"
  30479.  /****************************************************************************
  30480.  * This function initializes the file dialog library (by loading strings).
  30481.  *
  30482.  * Note: Initialization will fail if CCHSTRINGSMAX is smaller than the
  30483.  *       space taken up by all strings in the .rc file.  Fix by increasing
  30484.  *       CCHSTRINGSMAX in wintool.h and maybe also the initial heap size
  30485.  *       in wintool.def.
  30486.  *
  30487.  * Returns:
  30488.  *   TRUE if initialization successful
  30489.  *   FALSE otherwise
  30490.  \***************************************************************************/
  30491.  
  30492.  BOOL PASCAL InitLibrary()
  30493.  {
  30494.      int i;
  30495.      int cch;
  30496.      PSTR pch;
  30497.      PSTR pmem;
  30498.      int cchRemaining;
  30499.  
  30500.      /* allocate memory for strings */
  30501.      if (!(pch = (pmem = WinAllocMem(vhheap, cchRemaining = CCHSTRINGSMAX))))
  30502.          return FALSE;
  30503.  
  30504.      /* load strings from resource file */
  30505.      for (i = 0; i < CSTRINGS; i++) {
  30506.          cch = 1 + WinLoadString(HABX, vhModule, i, cchRemaining, (PSZ)pch);
  30507.          if (cch < 2)
  30508.              /* loadstring failed */
  30509.              return FALSE;
  30510.          vrgsz[i] = pch;
  30511.          pch += cch;
  30512.  
  30513.          if ((cchRemaining -= cch) <= 0)
  30514.              /* ran out of space */
  30515.              return FALSE;
  30516.      }
  30517.  
  30518.      /* reallocate string space to size actually needed */
  30519.      WinReallocMem(vhheap, pmem, CCHSTRINGSMAX, CCHSTRINGSMAX - cchRemaining);
  30520.  
  30521.      return TRUE;
  30522.  }
  30523.  
  30524.  
  30525.  JIGSAW.C
  30526.  CD-ROM Disc Path:   \SAMPCODE\OS2SDK\OS2SDK12\JIGSAW\JIGSAW.C
  30527.  
  30528.  /********************************** Jigsaw  *********************************
  30529.  /*
  30530.  /* Created 1988, Microsoft Corporation.
  30531.  /*
  30532.  /* Purpose:  To illustrate the use of Gpi retained segments.
  30533.  /*
  30534.  /* Summary:  This program provides a jigsaw puzzle, based on a decomposition
  30535.  /*   of an arbitrary bitmap loaded from a file.  The user can jumble the
  30536.  /*   pieces, then drag them individually by means of the mouse.  The image
  30537.  /*   can be zoomed in and out and scrolled up/down and left/right.
  30538.  /*
  30539.  /*   Each piece of the puzzle is a retained segment.  When a piece is
  30540.  /*   selected for dragging, it is made dynamic.  A menu option allows the
  30541.  /*   selected piece to be dragged as an outline or as a normal-looking piece.
  30542.  /*
  30543.  /*   Individual pieces are made to "move" by changing their model transforms.
  30544.  /*   Scrolling and zooming of the whole picture is done by changing the
  30545.  /*   default viewing transform.
  30546.  /*
  30547.  /* Optimizations:  While it is possible to implement this puzzle using a very
  30548.  /*   naive approach, this is liable to lead to a rather slowly-operating
  30549.  /*   program.  The following optimizations dramatically improve program
  30550.  /*   performance:
  30551.  /*
  30552.  /*   1> BitBlt only as much of the bitmap through a clip path as necessary.
  30553.  /*   Each piece of the puzzle is drawn by defining a clip path, blitting
  30554.  /*   through the path, and drawing an outline on the same path.  The naive
  30555.  /*   approach is to blit the whole bitmap through the clip path.  A more
  30556.  /*   clever approach is to compute the piece's bounding box and only use
  30557.  /*   the source and destination rectangles which correspond to this box.
  30558.  /*   This leads to an order-of-magnitude speedup in the time to draw one
  30559.  /*   piece.
  30560.  /*
  30561.  /*   2> Make the source and target rectangles for BitBlt the same size
  30562.  /*   in device coordinates.  A BitBlt in a retained segment must be done
  30563.  /*   with GpiWCBitBlt and the target rectangle must be specified in world
  30564.  /*   coordinates, so you must use GpiConvert (taking into account that in
  30565.  /*   world space rectangles are inclusive-inclusive while in device space
  30566.  /*   rectangles are inclusive-exclusive) to compute what target world space
  30567.  /*   rectangle will be converted to the desired device space rectangle.
  30568.  /*   Making the sizes of the source and converted target rectangles differ
  30569.  /*   by even one pel will cause strectching or compression to occur, with
  30570.  /*   a dramatic loss in speed.        Unfortunately, due to rounding effects,
  30571.  /*   not always possible to guarantee that adding an offset to the
  30572.  /*   transformation applied to a segment will leave the size of the
  30573.  /*   rectangle defined by the orders in the segment unchanged.
  30574.  /*
  30575.  /*   3> Use auxiliary information to reduce the number of segments which
  30576.  /*   must be checked for correlation.  The naive approach to hit-testing is
  30577.  /*   to test the whole chain, even though generally only a small fraction of
  30578.  /*   the segments in the chain could possibly get a hit.  A more clever
  30579.  /*   approach is to take the bounding box for each segment and only include
  30580.  /*   the segment in the correlation check if the box contains the correlation
  30581.  /*   point.  eg.
  30582.  /*    a> Edit the chain by adjusting the ATTR_CHAINED attribute of each
  30583.  /*    segment to reflect candidacy for being hit.  Afterwards, fix up by
  30584.  /*    adding back removed segments to the chain.
  30585.  /*    b> Even faster is to keep an auxiliary data structure which records
  30586.  /*    the priority of the segments (placed in the SEGLIST chain).  Run
  30587.  /*    through the priority list from high-priority to low-priority and do a
  30588.  /*    correlation test on each segment which passes the bounding-box test.
  30589.  /*
  30590.  /*   4> When repainting through a clip region, only draw those segments which
  30591.  /*   overlap the clip region.  The naive approach is to set up the clip
  30592.  /*   region and do a GpiDrawChain on the whole chain.  The drawback to this
  30593.  /*   is that much time will be spent running through the orders in segments
  30594.  /*   which are not visible through the clip region.  Very often, most of the
  30595.  /*   segments in the picture can be eliminated from needing to be drawn by
  30596.  /*   recognizing that there is no overlap between the bounding boxes of the
  30597.  /*   segment and the clip region.
  30598.  /*
  30599.  /*   5> Do WinScrollWindow horizontally in multiples of 8 pels when possible.
  30600.  /*   For example, horizontal scrolls by 7 or 9 pels are much slower than a
  30601.  /*   a horizontal scroll by 8 pels.
  30602.  /*
  30603.  /****************************************************************************
  30604.  
  30605.  #define INCL_BITMAPFILEFORMAT
  30606.  
  30607.  #define INCL_DOSPROCESS
  30608.  #define INCL_DOSSEMAPHORES
  30609.  #define INCL_DOSMEMMGR
  30610.  
  30611.  #define INCL_DEV
  30612.  
  30613.  #define INCL_WINWINDOWMGR
  30614.  #define INCL_WINMESSAGEMGR
  30615.  #define INCL_WININPUT
  30616.  #define INCL_WINRECTANGLES
  30617.  #define INCL_WINPOINTERS
  30618.  #define INCL_WINMENUS
  30619.  #define INCL_WINSCROLLBARS
  30620.  #define INCL_WINFRAMEMGR
  30621.  #define INCL_WINSWITCHLIST
  30622.  #define INCL_WINSYS
  30623.  
  30624.  #define INCL_GPIBITMAPS
  30625.  #define INCL_GPICONTROL
  30626.  #define INCL_GPITRANSFORMS
  30627.  #define INCL_GPIPRIMITIVES
  30628.  #define INCL_GPIMETAFILES
  30629.  #define INCL_GPIPATHS
  30630.  #define INCL_GPIREGIONS
  30631.  #define INCL_GPISEGMENTS
  30632.  #define INCL_GPISEGEDITING
  30633.  #define INCL_GPICORRELATION
  30634.  #define INCL_GPILCIDS
  30635.  
  30636.  #define INCL_ERRORS
  30637.  
  30638.  #include <os2.h>
  30639.  #include <stdlib.h>
  30640.  #include <stdio.h>
  30641.  #include <string.h>
  30642.  #include <opendlg.h>
  30643.  #include "noncomm.h"
  30644.  #include "jigsaw.h"
  30645.  
  30646.  
  30647.  
  30648.  /*----------------------- inter-thread messages -----------------------------
  30649.  
  30650.  UM_DIE              WM_USER+1        /* instruct async thread to terminate  *
  30651.  UM_DRAW       WM_USER+2        /* draw the current picture              */
  30652.  UM_VSCROLL    WM_USER+3        /* perform scroll by recalculating the */
  30653.                                         /* default viewing transform
  30654.  UM_HSCROLL    WM_USER+4        /* perform scroll by recalculating the */
  30655.                                         /* default viewing transform
  30656.  UM_SIZING     WM_USER+5        /* perform sizing by recalculating the */
  30657.                                         /* default viewing transform
  30658.  UM_ZOOM_IN    WM_USER+6        /* zoom the picture by recalculating   */
  30659.                                         /* the default viewing transform
  30660.  UM_ZOOM_OUT   WM_USER+7        /* zoom the picture by recalculating   */
  30661.                                         /* the default viewing transform
  30662.  #define UM_REDRAW     WM_USER+8
  30663.  #define UM_JUMBLE     WM_USER+9
  30664.  #define UM_LOAD       WM_USER+10
  30665.  UM_DUMMY      WM_USER+11       /* all commands not forcing redraw     */
  30666.                                         /* must come after this one
  30667.  
  30668.  UM_LEFTDOWN   WM_USER+12       /* mouse button down in the client area*/
  30669.                                         /* perform a correlation on the curren
  30670.                                         /* picture, setting any picked segment
  30671.                                         /* to dynamic
  30672.  UM_MOUSEMOVE  WM_USER+13       /* mousemove command, remove, repositon*/
  30673.                                         /* and redraw any dynamic sements
  30674.  UM_LEFTUP     WM_USER+14       /* mouse button up in the client area  */
  30675.                                         /* set any dynamic segment to normal
  30676.  UM_FASTDRAG   WM_USER+15       /* toggle fast-drag (outline) mode     */
  30677.  UM_DRAWDONE   WM_USER+16       /* Async DrawChain has completed       */
  30678.  #define UM_FLUSH      WM_USER+17
  30679.  
  30680.  
  30681.  /*------------------------ element label values  ----------------------------
  30682.  
  30683.  #define FILLPATH       222L
  30684.  #define BITBLT_TOP     232L
  30685.  #define BITBLT_BOTTOM  233L
  30686.  
  30687.  
  30688.  /*------------------------- correlation parameters --------------------------
  30689.  
  30690.  HITS        1L                       /* maximum number of hits to return    *
  30691.  DEPTH        2L                       /* max depth of seg calls to return
  30692.  
  30693.  
  30694.  /*-------------------------- general definitions ----------------------------
  30695.  
  30696.  
  30697.  HAB        habMain=NULL;                       /* main thread anchor block ha
  30698.  HMQ        hmqMain=NULL;                       /* main thread queue handle
  30699.  HWND    hwndFrame=NULL;                /* frame control handle
  30700.  HWND        hwndClient=NULL;               /* client area handle
  30701.  HDC        hdcClient=NULL;                /* window dc handle
  30702.  HPS        hpsClient=NULL;                /* client area Gpi ps handle
  30703.  SIZEL        sizlMaxClient;                       /* max client area size
  30704.  HPS     hpsPaint=NULL;                 /* ps for use in Main Thread
  30705.  HRGN        hrgnInvalid = NULL;               /* handle to the invalid region
  30706.  
  30707.  HAB        habAsync=NULL;                       /* async thread anchor block
  30708.  HMQ        hmqAsync=NULL;                       /* async thread queue handle
  30709.  TID     tidAsync;                      /* async thread id
  30710.  SEL        selStack;                       /* async thread stack selector
  30711.  STACKSIZE  4096                /* async thread stack size              */
  30712.  SHORT        sPrty = -1;                       /* async thread priority
  30713.  
  30714.  HWND        hwndHorzScroll=NULL;               /* horizontal scroll bar windo
  30715.  HWND        hwndVertScroll=NULL;               /* vertical scroll bar window
  30716.  POINTS        ptsScrollPos, ptsOldScrollPos;
  30717.  POINTS        ptsScrollMax, ptsHalfScrollMax;
  30718.  POINTS        ptsScrollLine = { 8, 8};
  30719.  POINTS        ptsScrollPage = { 64, 64};
  30720.  
  30721.  #define UNITY               65536L
  30722.  MATRIXLF matlfIdentity = { UNITY, 0, 0, 0, UNITY, 0, 0, 0, 1 };
  30723.  LONG        lScale = 0;                       /* current zoom level
  30724.  #define ZOOM_MAX       8
  30725.  #define ZOOM_IN_ARG    1
  30726.  #define ZOOM_OUT_ARG   -1
  30727.  
  30728.  #define CALLSEG_BASE   1000
  30729.  POINTL        ptlOffset;
  30730.  POINTL        ptlBotLeft  = { 0, 0};
  30731.  POINTL        ptlTopRight = { 300, 300};
  30732.  LONG        lLastSegId;                       /* last segment id assigned to
  30733.  LONG        lPickedSeg;                       /* seg id of piece selected for
  30734.  RECTL        rclBounds;                       /* pict bounding box in model c
  30735.  POINTL        ptlOldMouse = {0L, 0L};        /* current mouse posn
  30736.  BOOL        fButtonDown = FALSE;               /* only drag if mouse down
  30737.  BOOL        fFastDrag = FALSE;               /* show only outline of dragging
  30738.  
  30739.  
  30740.  /*-------------------------- segment list -----------------------------------
  30741.  
  30742.  typedef struct _SEGLIST {               /* sl
  30743.      LONG                  lSegId;
  30744.      struct _SEGLIST FAR * pslPrev;
  30745.      struct _SEGLIST FAR * pslNext;
  30746.      POINTL                  ptlLocation; /* piece location, world coordinates
  30747.      RECTL                  rclCurrent;  /* segment bounding box, model coords
  30748.      RECTL                  rclBitBlt;   /* segment bounding box, world coords
  30749.  } SEGLIST ;
  30750.  typedef SEGLIST FAR *PSEGLIST;               /* psl
  30751.  typedef PSEGLIST FAR *PPSEGLIST;       /* ppsl
  30752.  PSEGLIST pslHead = NULL;               /* head of the list
  30753.  PSEGLIST pslTail = NULL;               /* tail of the list
  30754.  PSEGLIST pslPicked = NULL;               /* picked segment's list member
  30755.  #define   ADD_HEAD_SEG         1
  30756.  #define   ADD_TAIL_SEG         2
  30757.  #define        DEL_SEG         3
  30758.  
  30759.  /*-------------------------- bitmap-related data ----------------------------
  30760.  
  30761.  typedef struct _LOADINFO {               /* li
  30762.      HFILE   hf;
  30763.      CHAR    szFileName[MAX_FNAME_LEN];
  30764.  } LOADINFO ;
  30765.  typedef LOADINFO FAR *PLOADINFO;       /* pli
  30766.  
  30767.  HPS                   hpsBitmapFile=NULL, hpsBitmapTemp=NULL, hpsBitmapDrag=N
  30768.  HDC                   hdcBitmapFile=NULL, hdcBitmapTemp=NULL, hdcBitmapDrag=N
  30769.  HBITMAP            hbmBitmapFile=NULL, hbmBitmapTemp=NULL, hbmBitmapDrag=NULL
  30770.  BITMAPINFOHEADER   bmpBitmapFile   = {12L, 0, 0, 0, 0};
  30771.  BITMAPINFOHEADER   bmpBitmapTemp   = {12L, 0, 0, 0, 0};
  30772.  BITMAPINFOHEADER   bmpBitmapDrag   = {12L, 0, 0, 0, 0};
  30773.  BITMAPINFO           bmiBitmap           = {12L, 0, 0, 0, 0, {{0, 0, 0}}};
  30774.  static DEVOPENSTRUC dop = { NULL
  30775.                            , "DISPLAY"
  30776.                            , NULL
  30777.                            , NULL
  30778.                            , NULL
  30779.                            , NULL
  30780.                            , NULL
  30781.                            , NULL
  30782.                            , NULL };
  30783.  
  30784.  
  30785.  /*-------------------------- old-style bitmap header ------------------------
  30786.  
  30787.  typedef struct {
  30788.      USHORT    wType;
  30789.      ULONG     dwSize;
  30790.      int       xHotspot;
  30791.      int       yHotspot;
  30792.      ULONG     dwBitsOffset;
  30793.      USHORT    bmWidth;
  30794.      USHORT    bmHeight;
  30795.      USHORT    bmPlanes;
  30796.      USHORT    bmBitcount;
  30797.  } RCBITMAP;
  30798.  typedef RCBITMAP FAR *PRCBITMAP;
  30799.  
  30800.  
  30801.  /*--------------------------- Miscellaneous ---------------------------------
  30802.  
  30803.  ULONG        ulTerminateSem = 0;               /* main thread blocks while as
  30804.  HSEM        hsemTerminate  = &ulTerminateSem;
  30805.  
  30806.  ULONG        ulSzFmt   = 0;                       /* serializes access to spr
  30807.  HSEM        hsemSzFmt = &ulSzFmt;
  30808.  CHAR        szFmt[50];                       /* buffer used by sprintf()
  30809.  
  30810.  SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE, SWL_JUMPABLE, 0, 0 };
  30811.  HSWITCH hsw;                               /* handle to a switch list entry
  30812.  char        szTitle[80];                       /* Title bar text
  30813.  
  30814.  BOOL        fErrMem = FALSE;               /* set if alloc async stack fails
  30815.  
  30816.  
  30817.  /*------------------------- Function Prototypes -----------------------------
  30818.  
  30819.  VOID         CalcBounds( VOID);
  30820.  VOID         CalcTransform( HWND);
  30821.  MRESULT CALLBACK ClientWndProc( HWND, USHORT, MPARAM, MPARAM);
  30822.  BOOL         CreateBitmapHdcHps( HDC, HPS);
  30823.  BOOL         CreateThread( VOID);
  30824.  BOOL         CreatePicture( VOID);
  30825.  VOID         DestroyThread( VOID);
  30826.  BOOL         DoDraw( HRGN);
  30827.  VOID         DoHorzScroll( VOID);
  30828.  VOID         DoVertScroll( VOID);
  30829.  BOOL         DumpPicture( VOID);
  30830.  VOID         Finalize( VOID);
  30831.  BOOL         Initialize( VOID);
  30832.  VOID         Jumble( VOID);
  30833.  VOID         LeftDown( MPARAM);
  30834.  VOID         LeftUp( VOID);
  30835.  VOID         Load( PLOADINFO);
  30836.  VOID cdecl main( VOID);
  30837.  VOID         MessageInt( HWND, INT, PCH);
  30838.  VOID         MouseMove( MPARAM);
  30839.  VOID         MyMessageBox( HWND, PSZ);
  30840.  VOID FAR NewThread( VOID);
  30841.  BOOL         PrepareBitmap( VOID);
  30842.  BOOL         ReadBitmap( HFILE);
  30843.  VOID         Redraw( VOID);
  30844.  VOID         ReportError( HAB);
  30845.  BOOL         SegListCheck( INT);
  30846.  PSEGLIST SegListGet( LONG);
  30847.  BOOL         SegListUpdate( USHORT, PSEGLIST);
  30848.  BOOL         SendCommand( USHORT, ULONG);
  30849.  VOID         SetDVTransform( FIXED, FIXED, FIXED, FIXED, LONG, LONG, LONG);
  30850.  VOID         SetRect( PSEGLIST);
  30851.  VOID         ToggleFastDrag( VOID);
  30852.  VOID         Translate( PSEGLIST, PPOINTL);
  30853.  MRESULT  WndProcCommand( HWND, USHORT, MPARAM, MPARAM);
  30854.  MRESULT  WndProcCreate( HWND);
  30855.  MRESULT  WndProcPaint( VOID);
  30856.  MRESULT  WndProcSize( MPARAM, MPARAM);
  30857.  VOID         Zoom( SHORT);
  30858.  VOID         ZoomMenuItems( VOID);
  30859.  
  30860.  
  30861.  /****************************************************************************
  30862.  /*
  30863.  /*  MyMessageBox
  30864.  /*
  30865.  /*  Displays a message box with the given string.  To simplify matters,
  30866.  /*  the box will always have the same title ("Jigsaw"), will always
  30867.  /*  have a single button ("Ok"), will always have an exclamation point
  30868.  /*  icon, and will always be application modal.
  30869.  /*
  30870.  /****************************************************************************
  30871.  VOID
  30872.  MyMessageBox( hWnd, psz)
  30873.  
  30874.  HWND  hWnd;
  30875.  PSZ   psz;
  30876.  {
  30877.      WinMessageBox( HWND_DESKTOP
  30878.                   , hWnd
  30879.                   , psz
  30880.                   , szTitle
  30881.                   , 0
  30882.                   , MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL );
  30883.  }
  30884.  
  30885.  /****************************************************************************
  30886.  /*
  30887.  /* Main thread will initialize the process for PM services and process
  30888.  /* the application message queue until a WM_QUIT message is received. It will
  30889.  /* then destroy all PM resources and terminate. Any error during
  30890.  /* initialization will be reported and the process terminated.
  30891.  /*
  30892.  /****************************************************************************
  30893.  VOID cdecl
  30894.  main()
  30895.  {
  30896.    QMSG        qmsg;
  30897.  
  30898.    if( Initialize())
  30899.        while( WinGetMsg( habMain, &qmsg, NULL, 0, 0))
  30900.            WinDispatchMsg( habMain, &qmsg);
  30901.    else
  30902.        ReportError( habMain);
  30903.    Finalize();
  30904.  }
  30905.  
  30906.  
  30907.  /****************************************************************************
  30908.  /*
  30909.  /* The Initialize function will initialize the PM interface,
  30910.  /* create an application message queue, a standard frame window and a new
  30911.  /* thread to control drawing operations.  It will also initialize static
  30912.  /* strings.
  30913.  /*
  30914.  /****************************************************************************
  30915.  BOOL
  30916.  Initialize()
  30917.  {
  30918.    ULONG   flCreate;
  30919.    PID          pid;
  30920.    TID          tid;
  30921.  
  30922.    WinShowPointer( HWND_DESKTOP, TRUE);
  30923.    habMain = WinInitialize( 0);
  30924.    if( !habMain)
  30925.        return( FALSE);
  30926.  
  30927.    hmqMain = WinCreateMsgQueue( habMain,0);
  30928.    if( !hmqMain)
  30929.        return( FALSE);
  30930.  
  30931.    WinLoadString( habMain, (HMODULE) NULL, TITLEBAR, sizeof(szTitle), szTitle)
  30932.    if( !WinRegisterClass( habMain
  30933.                         , (PCH)szTitle
  30934.                         , (PFNWP)ClientWndProc
  30935.                         , CS_SIZEREDRAW
  30936.                         , 0 ))
  30937.        return( FALSE);
  30938.  
  30939.    flCreate =   (FCF_STANDARD | FCF_VERTSCROLL | FCF_HORZSCROLL)
  30940.               & ~(ULONG)FCF_TASKLIST;
  30941.    hwndFrame = WinCreateStdWindow( HWND_DESKTOP
  30942.                                  , WS_VISIBLE
  30943.                                  , &flCreate
  30944.                                  , szTitle
  30945.                                  , szTitle
  30946.                                  , WS_VISIBLE
  30947.                                  , (HMODULE) NULL
  30948.                                  , APPMENU
  30949.                                  , &hwndClient);
  30950.    if( !hwndFrame)
  30951.        return( FALSE);
  30952.  
  30953.    WinQueryWindowProcess( hwndFrame, &pid, &tid);
  30954.    swctl.hwnd          = hwndFrame;
  30955.    swctl.idProcess = pid;
  30956.    lstrcpy( swctl.szSwtitle, szTitle);
  30957.    hsw = WinAddSwitchEntry( &swctl);
  30958.  
  30959.    if( !CreateThread())                      /* create async thread
  30960.        return ( FALSE);
  30961.    if( !CreateBitmapHdcHps( &hdcBitmapFile, &hpsBitmapFile))
  30962.        return( FALSE);
  30963.    if( !CreateBitmapHdcHps( &hdcBitmapTemp, &hpsBitmapTemp))
  30964.        return( FALSE);
  30965.    if( !CreateBitmapHdcHps( &hdcBitmapDrag, &hpsBitmapDrag))
  30966.        return( FALSE);
  30967.  
  30968.    return( TRUE);
  30969.  }
  30970.  
  30971.  /****************************************************************************
  30972.  /*
  30973.  /* Finalize will destroy the asynchronous drawing thread, all Presentation
  30974.  /* Manager resources, and terminate the process.
  30975.  /*
  30976.  /****************************************************************************
  30977.  VOID
  30978.  Finalize()
  30979.  {
  30980.    DestroyThread();
  30981.  
  30982.    while( pslHead != NULL )
  30983.        SegListUpdate( DEL_SEG, pslHead);
  30984.    if( hrgnInvalid)
  30985.        GpiDestroyRegion( hpsClient, hrgnInvalid);
  30986.    if( hpsClient)
  30987.        GpiAssociate( hpsClient, NULL);
  30988.    if( hpsPaint)
  30989.        GpiAssociate( hpsPaint, NULL);
  30990.    if( hpsBitmapFile)
  30991.        GpiAssociate( hpsBitmapFile, NULL);
  30992.    if( hpsBitmapTemp)
  30993.        GpiAssociate( hpsBitmapTemp, NULL);
  30994.    if( hpsBitmapDrag)
  30995.        GpiAssociate( hpsBitmapDrag, NULL);
  30996.    if( hwndFrame)
  30997.        WinDestroyWindow( hwndFrame);
  30998.    if( hmqMain)
  30999.        WinDestroyMsgQueue( hmqMain);
  31000.    if( habMain)
  31001.        WinTerminate( habMain);
  31002.  
  31003.    DosExit( EXIT_PROCESS, 0);
  31004.  }
  31005.  
  31006.  
  31007.  /****************************************************************************
  31008.  /*
  31009.  /* ReportError        will display the latest error information for the requi
  31010.  /* thread. No resources to be loaded if out of memory error.
  31011.  /*
  31012.  /****************************************************************************
  31013.  VOID
  31014.  ReportError( hab)
  31015.  
  31016.  HAB hab;
  31017.  {
  31018.    PERRINFO  perriBlk;
  31019.    PSZ            pszErrMsg;
  31020.    USHORT *  TempPtr;
  31021.  
  31022.    if( !hwndFrame)
  31023.        return;
  31024.    if( !fErrMem)
  31025.    {
  31026.        perriBlk = WinGetErrorInfo(hab);
  31027.        if( !perriBlk)
  31028.            return;
  31029.        SELECTOROF( pszErrMsg) = SELECTOROF(perriBlk);
  31030.        SELECTOROF( TempPtr)   = SELECTOROF(perriBlk);
  31031.        OFFSETOF( TempPtr)     = perriBlk->offaoffszMsg;
  31032.        OFFSETOF( pszErrMsg)   = *TempPtr;
  31033.        WinMessageBox( HWND_DESKTOP
  31034.                     , hwndFrame
  31035.                     , pszErrMsg
  31036.                     , szTitle
  31037.                     , 0
  31038.                     , MB_CUACRITICAL | MB_ENTER);
  31039.        WinFreeErrorInfo( perriBlk);
  31040.    } else
  31041.        WinMessageBox( HWND_DESKTOP
  31042.                     , hwndFrame
  31043.                     , "ERROR - Out Of Memory"
  31044.                     , szTitle
  31045.                     , 0
  31046.                     , MB_CUACRITICAL | MB_ENTER);
  31047.  }
  31048.  
  31049.  
  31050.  /****************************************************************************
  31051.  /*
  31052.  /* CreateThread  creates the asynchronous drawing thread. It will allocate
  31053.  /* stack space and create the thread.
  31054.  /*
  31055.  /****************************************************************************
  31056.  BOOL
  31057.  CreateThread()
  31058.  {
  31059.    PBYTE pbAsyncStack;                      /* long pointer to stack for new t
  31060.  
  31061.  
  31062.    if( DosAllocSeg( STACKSIZE, (PSEL)&selStack, 0 ))
  31063.    {
  31064.        fErrMem = TRUE;
  31065.        return( FALSE);
  31066.    }
  31067.    OFFSETOF(pbAsyncStack) = STACKSIZE-2;
  31068.    SELECTOROF(pbAsyncStack) = selStack;
  31069.    if( DosCreateThread( (PFNTHREAD)NewThread, &tidAsync, pbAsyncStack ))
  31070.        return( FALSE);
  31071.    return( TRUE);
  31072.  }
  31073.  
  31074.  
  31075.  /****************************************************************************
  31076.  /*
  31077.  /* DestroyThread  will send a message  to the asynchronous drawing thread
  31078.  /* commanding it to terminate itself. If the send is successful it will wait
  31079.  /* until the async thread has terminated. It will then release any stack spac
  31080.  /* used by that thread.
  31081.  /*
  31082.  /****************************************************************************
  31083.  VOID
  31084.  DestroyThread()
  31085.  {
  31086.    if( tidAsync)
  31087.    {
  31088.        DosSemSet( hsemTerminate);
  31089.        if( SendCommand( (USHORT)UM_DIE, (ULONG)NULL))
  31090.            DosSemWait( hsemTerminate, SEM_INDEFINITE_WAIT);
  31091.    }
  31092.    if( selStack)
  31093.        DosFreeSeg( selStack);
  31094.  }
  31095.  
  31096.  
  31097.  /****************************************************************************
  31098.  /*
  31099.  /* SendCommand        will attempt to post the required command and parameter
  31100.  /* the asynchronous drawing thread's message queue. The command will only
  31101.  /* be posted if the queue exists.
  31102.  /*
  31103.  /****************************************************************************
  31104.  BOOL
  31105.  SendCommand( usCommand, ulInfo)
  31106.  
  31107.  USHORT        usCommand;
  31108.  ULONG        ulInfo;
  31109.  {
  31110.    if( !hmqAsync)
  31111.        return( FALSE);
  31112.  
  31113.    switch( usCommand)
  31114.    {
  31115.      case UM_DIE:
  31116.      case UM_LEFTDOWN:
  31117.      case UM_LEFTUP:
  31118.      case UM_MOUSEMOVE:
  31119.      case UM_DRAW:
  31120.      case UM_HSCROLL:
  31121.      case UM_VSCROLL:
  31122.      case UM_ZOOM_IN:
  31123.      case UM_ZOOM_OUT:
  31124.      case UM_REDRAW:
  31125.      case UM_SIZING:
  31126.      case UM_FASTDRAG:
  31127.      case UM_JUMBLE:
  31128.      case UM_LOAD:
  31129.  
  31130.          return( WinPostQueueMsg( hmqAsync
  31131.                                 , usCommand
  31132.                                 , MPFROMLONG( ulInfo)
  31133.                                 , MPFROMLONG( NULL  ) ) );
  31134.          break;
  31135.  
  31136.      default:
  31137.          return( TRUE);
  31138.    }
  31139.  }
  31140.  
  31141.  
  31142.  /****************************************************************************
  31143.  /*
  31144.  /* ClientWndProd is the window procedure associated with the client window.
  31145.  /*
  31146.  /****************************************************************************
  31147.  MRESULT CALLBACK
  31148.  ClientWndProc( hwnd, msg, mp1, mp2)
  31149.  
  31150.  HWND        hwnd;
  31151.  USHORT  msg;
  31152.  MPARAM        mp1;
  31153.  MPARAM        mp2;
  31154.  {
  31155.    CHAR  szTemp[128];
  31156.  
  31157.    switch( msg)
  31158.    {
  31159.      case WM_CREATE:
  31160.        return( WndProcCreate( hwnd));
  31161.        break;
  31162.  
  31163.      case WM_CLOSE:
  31164.        WinLoadString( habMain, (HMODULE) NULL, TERMINATE, sizeof(szTemp), (PSZ
  31165.        if( WinMessageBox( HWND_DESKTOP
  31166.                         , hwndFrame
  31167.                         , szTemp
  31168.                         , szTitle
  31169.                         , 0
  31170.                         , MB_CUAWARNING | MB_YESNO | MB_DEFBUTTON2)
  31171.                 == MBID_YES)
  31172.            WinPostMsg( hwnd, WM_QUIT, NULL, NULL);
  31173.        break;
  31174.  
  31175.      case WM_PAINT:
  31176.        return( WndProcPaint());
  31177.        break;
  31178.  
  31179.      /************************************************************************
  31180.      /*
  31181.      /************************************************************************
  31182.      case WM_ERASEBACKGROUND:
  31183.        WinFillRect( (HPS)mp1, (PRECTL)mp2, CLR_BACKGROUND);
  31184.        return( FALSE);
  31185.        break;
  31186.  
  31187.      /************************************************************************
  31188.      /*
  31189.      /************************************************************************
  31190.      case WM_MINMAXFRAME:
  31191.        if( (((PSWP)mp1)->fs & SWP_RESTORE)  ||
  31192.            (((PSWP)mp1)->fs & SWP_MAXIMIZE) )
  31193.          SendCommand( (USHORT)UM_SIZING, 0L);
  31194.        break;
  31195.  
  31196.      /************************************************************************
  31197.      /* Process menu item commands, and commands generated from the keyboard
  31198.      /* via the accelerator table. Most are handled by the async thread
  31199.      /************************************************************************
  31200.      case WM_COMMAND:
  31201.        return( WndProcCommand( hwnd, msg, mp1, mp2));
  31202.        break;
  31203.  
  31204.      /************************************************************************
  31205.      /* Scrolling is handled by the async drawing thread. Simply pass on the
  31206.      /* command and parameters
  31207.      /************************************************************************
  31208.      case WM_HSCROLL:
  31209.        SendCommand( (USHORT)UM_HSCROLL, LONGFROMMP(mp2));
  31210.        break;
  31211.  
  31212.      case WM_VSCROLL:
  31213.        SendCommand( (USHORT)UM_VSCROLL, LONGFROMMP(mp2));
  31214.        break;
  31215.  
  31216.      /************************************************************************
  31217.      /* The client area is being resized.                                    *
  31218.      /************************************************************************
  31219.      case WM_SIZE:
  31220.        return( WndProcSize( mp1, mp2));
  31221.        break;
  31222.  
  31223.      /************************************************************************
  31224.      /* Mouse commands are handled by the async thread. Simply send on the
  31225.      /* command and parameters.
  31226.      /************************************************************************
  31227.      case WM_BUTTON1DBLCLK:
  31228.      case WM_BUTTON1DOWN:
  31229.        if( hwnd != WinQueryFocus( HWND_DESKTOP, FALSE))
  31230.            WinSetFocus( HWND_DESKTOP, hwnd);
  31231.        if( !fButtonDown)
  31232.        {
  31233.            fButtonDown = TRUE;
  31234.            SendCommand( (USHORT)UM_LEFTDOWN, LONGFROMMP(mp1));
  31235.        }
  31236.        return((MRESULT) TRUE);
  31237.        break;
  31238.  
  31239.      case WM_BUTTON1UP:
  31240.        if( !fButtonDown)
  31241.            return((MRESULT) TRUE);
  31242.        if( SendCommand( (USHORT)UM_LEFTUP, LONGFROMMP(mp1)))
  31243.            fButtonDown = FALSE;
  31244.        else
  31245.            WinAlarm( HWND_DESKTOP, WA_WARNING);
  31246.        return((MRESULT) TRUE);
  31247.        break;
  31248.  
  31249.      case WM_MOUSEMOVE:
  31250.        if( fButtonDown && (pslPicked != NULL))
  31251.            SendCommand( (USHORT)UM_MOUSEMOVE, LONGFROMMP(mp1));
  31252.        return( WinDefWindowProc( hwnd, msg, mp1, mp2));
  31253.        break;
  31254.  
  31255.      /************************************************************************
  31256.      /* Default for the rest
  31257.      /************************************************************************
  31258.      default:
  31259.        return( WinDefWindowProc( hwnd, msg, mp1, mp2));
  31260.    }
  31261.  
  31262.    return( FALSE);
  31263.  }
  31264.  
  31265.  /****************************************************************************
  31266.  /*
  31267.  /* Get the maximum client area size.  Create a window DC for the client
  31268.  /* area and a normal GPI Presentation Space and associate the two.  The GPI
  31269.  /* PS will be the maximum client area size and be in pels.
  31270.  /*
  31271.  /****************************************************************************
  31272.  MRESULT
  31273.  WndProcCreate( hwnd)
  31274.  
  31275.  HWND  hwnd;
  31276.  {
  31277.    SIZEL sizlPickApp;                      /* pick aperture size
  31278.  
  31279.    sizlMaxClient.cx = WinQuerySysValue( HWND_DESKTOP, SV_CXFULLSCREEN);
  31280.    sizlMaxClient.cy = WinQuerySysValue( HWND_DESKTOP, SV_CYFULLSCREEN);
  31281.  
  31282.    hdcClient = WinOpenWindowDC( hwnd);
  31283.    hpsClient = GpiCreatePS( habMain
  31284.                           , hdcClient
  31285.                           , &sizlMaxClient
  31286.                           , GPIA_ASSOC | PU_PELS );
  31287.    if( !hpsClient)
  31288.        return((MRESULT) TRUE);
  31289.    GpiSetAttrMode( hpsClient, AM_PRESERVE);
  31290.  
  31291.    hwndHorzScroll = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT, FALSE)
  31292.                                    , FID_HORZSCROLL);
  31293.  
  31294.    hwndVertScroll = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT, FALSE)
  31295.                                    , FID_VERTSCROLL);
  31296.  
  31297.    hpsPaint = GpiCreatePS( habMain, NULL, &sizlMaxClient, PU_PELS);
  31298.  
  31299.    hrgnInvalid = GpiCreateRegion( hpsClient, 0L, NULL);
  31300.  
  31301.    sizlPickApp.cx = sizlPickApp.cy = 1;
  31302.    GpiSetPickApertureSize( hpsClient, PICKAP_REC, &sizlPickApp);
  31303.    return( FALSE);
  31304.  }
  31305.  
  31306.  
  31307.  /****************************************************************************
  31308.  /*
  31309.  /* WM_PAINT message
  31310.  /*
  31311.  /****************************************************************************
  31312.  MRESULT
  31313.  WndProcPaint()
  31314.  
  31315.  {
  31316.    HRGN         hrgnUpdt;
  31317.    SHORT  sRgnType;
  31318.  
  31319.    hrgnUpdt = GpiCreateRegion( hpsPaint, 0L, NULL);
  31320.    sRgnType = WinQueryUpdateRegion( hwndClient, hrgnUpdt);
  31321.    WinValidateRegion( hwndClient, hrgnUpdt, FALSE);
  31322.    SendCommand( UM_DRAW, (ULONG)hrgnUpdt);
  31323.    return( FALSE);
  31324.  }
  31325.  
  31326.  /****************************************************************************
  31327.  /* Process menu item commands, and commands generated from the keyboard via
  31328.  /* the accelerator table.  Most are handled by the async thread
  31329.  /****************************************************************************
  31330.  MRESULT
  31331.  WndProcCommand( hwnd, msg, mp1, mp2)
  31332.  
  31333.  HWND        hwnd;
  31334.  USHORT  msg;
  31335.  MPARAM        mp1, mp2;
  31336.  {
  31337.    CHAR            szTemp[128];
  31338.    DLF            dlf;
  31339.    SEL            sel;
  31340.    PLOADINFO pli;
  31341.    PSZ            pszError, psz1, psz2;
  31342.  
  31343.    switch( SHORT1FROMMP(mp1))
  31344.    {
  31345.      case MENU_JUMBLE:
  31346.          SendCommand( UM_JUMBLE, 0L);
  31347.          break;
  31348.  
  31349.      case MENU_LOAD:
  31350.          DosAllocSeg( sizeof( LOADINFO), &sel, 0);
  31351.          pli = MAKEP( sel, 0);
  31352.  
  31353.          dlf.rgbAction            = DLG_OPENDLG;
  31354.          dlf.rgbFlags            = ATTRDIRLIST;
  31355.          dlf.phFile            = &(pli->hf);
  31356.          dlf.pszExt            = (PSZ)"\\*.bmp";
  31357.          dlf.pszAppName            = szTitle;
  31358.          dlf.pszTitle            = "Load Bitmap";
  31359.          dlf.pszInstructions = NULL;
  31360.          dlf.szFileName[0]   = '\0';
  31361.          dlf.szOpenFile[0]   = '\0';
  31362.          pszError            = "Error reading file.";
  31363.  
  31364.          switch( DlgFile( hwnd, &dlf))
  31365.          {
  31366.            case TDF_ERRMEM:
  31367.            case TDF_INVALID:
  31368.                MyMessageBox( hwnd, pszError);
  31369.                break;
  31370.  
  31371.            case TDF_NOOPEN:
  31372.                break;
  31373.  
  31374.            default:
  31375.                for( psz1 = dlf.szFileName, psz2 = pli->szFileName
  31376.                   ; *psz2++ = *psz1++
  31377.                   ; )
  31378.                    ;
  31379.                SendCommand( UM_LOAD, (LONG)pli);
  31380.                break;
  31381.          }
  31382.          break;
  31383.      /**********************************************************************/
  31384.      /* EXIT command, menu item or F3 key pressed. Give the operator a
  31385.      /* second chance, if confirmed post a WM_QUIT msg to the application  */
  31386.      /* msg queue. This will force the MAIN thread to terminate.           */
  31387.      /**********************************************************************/
  31388.      case MENU_EXIT:
  31389.        WinLoadString( habMain, (HMODULE) NULL, TERMINATE, sizeof(szTemp), szTe
  31390.        if( WinMessageBox( HWND_DESKTOP
  31391.                         , hwndFrame
  31392.                         , szTemp
  31393.                         , szTitle
  31394.                         , 0
  31395.                         , MB_CUAWARNING | MB_YESNO | MB_DEFBUTTON2)
  31396.              == MBID_YES)
  31397.          WinPostMsg( hwnd, WM_QUIT, NULL, NULL);
  31398.        break;
  31399.  
  31400.      /**********************************************************************/
  31401.      /* Pass on the rest to the async thread.
  31402.      /**********************************************************************/
  31403.      case MENU_ZOOMIN:
  31404.        SendCommand( UM_ZOOM_IN, 0L);
  31405.        break;
  31406.  
  31407.      case MENU_ZOOMOUT:
  31408.        SendCommand( UM_ZOOM_OUT, 0L);
  31409.        break;
  31410.  
  31411.      case MENU_FASTDRAG:
  31412.        SendCommand( UM_FASTDRAG, 0L);
  31413.        break;
  31414.  
  31415.      /**********************************************************************/
  31416.      /* Unrecognised => default
  31417.      /**********************************************************************/
  31418.      default:
  31419.        return( WinDefWindowProc(hwnd, msg, mp1, mp2));
  31420.    }
  31421.    return( FALSE);
  31422.  }
  31423.  
  31424.  /****************************************************************************
  31425.  /* Load a bitmap
  31426.  /****************************************************************************
  31427.  VOID
  31428.  Load( pli)
  31429.  
  31430.  PLOADINFO  pli;
  31431.  {
  31432.      PSZ     pszError;
  31433.      RECTL   rclClient;
  31434.  
  31435.      pszError = (PSZ)"Error reading file.";
  31436.  
  31437.      DumpPicture();
  31438.      if( !ReadBitmap( pli->hf) )
  31439.      {
  31440.        MyMessageBox( hwndClient, pszError);
  31441.        return;
  31442.      }
  31443.      if( !PrepareBitmap() )
  31444.      {
  31445.        MyMessageBox( hwndClient, pszError);
  31446.        return;
  31447.      }
  31448.  
  31449.      lstrcpy( swctl.szSwtitle, szTitle);
  31450.      lstrcat( swctl.szSwtitle, ": ");
  31451.      lstrcat( swctl.szSwtitle, pli->szFileName);
  31452.      WinChangeSwitchEntry( hsw, &swctl);
  31453.      WinSetWindowText( hwndFrame, swctl.szSwtitle);
  31454.  
  31455.      CreatePicture();
  31456.      lScale = 0;
  31457.  
  31458.      WinQueryWindowRect( hwndClient, &rclClient);
  31459.      ptsScrollMax.x = (SHORT)(rclClient.xRight - rclClient.xLeft);
  31460.      ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
  31461.      ptsScrollPos.x = ptsHalfScrollMax.x;
  31462.      ptsOldScrollPos.x = ptsHalfScrollMax.x;
  31463.      WinSendMsg( hwndHorzScroll
  31464.                , SBM_SETSCROLLBAR
  31465.                , MPFROMSHORT( ptsScrollPos.x)
  31466.                , MPFROM2SHORT( 1, ptsScrollMax.x) );
  31467.      ptsScrollMax.y = (SHORT)(rclClient.yTop - rclClient.yBottom);
  31468.      ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
  31469.      ptsScrollPos.y = ptsHalfScrollMax.y;
  31470.      ptsOldScrollPos.y = ptsHalfScrollMax.y;
  31471.      WinSendMsg( hwndVertScroll
  31472.                , SBM_SETSCROLLBAR
  31473.                , MPFROMSHORT( ptsScrollPos.y)
  31474.                , MPFROM2SHORT( 1, ptsScrollMax.y) );
  31475.  
  31476.      CalcBounds();
  31477.      CalcTransform( hwndClient);
  31478.      DosFreeSeg( SELECTOROF( pli));
  31479.  }
  31480.  /****************************************************************************
  31481.  /* Throw the pieces around the screen.
  31482.  /****************************************************************************
  31483.  VOID
  31484.  Jumble()
  31485.  {
  31486.    LONG            lWidth, lHeight;
  31487.    DATETIME  date;
  31488.    POINTL    ptl;
  31489.    RECTL     rclClient;
  31490.    PSEGLIST  psl;
  31491.  
  31492.    if( WinQueryWindowRect( hwndClient, &rclClient) )
  31493.    {
  31494.      lWidth  = rclClient.xRight - rclClient.xLeft;
  31495.      lHeight = rclClient.yTop   - rclClient.yBottom;
  31496.      if( (lWidth > 0) && (lHeight > 0) )
  31497.      {
  31498.        DosGetDateTime( &date);
  31499.        srand( (USHORT)date.hundredths);
  31500.        for( psl = pslHead; psl != NULL; psl = psl->pslNext)
  31501.        {
  31502.          ptl.x = rclClient.xLeft   + (rand() % lWidth);
  31503.          ptl.y = rclClient.yBottom + (rand() % lHeight);
  31504.          Translate( psl, &ptl);
  31505.          SetRect( psl);
  31506.        }
  31507.      }
  31508.    }
  31509.  }
  31510.  
  31511.  /****************************************************************************
  31512.  /* The client area is being resized.  The current scroll bar thumb position
  31513.  /* and scroll bar range must be recalculated prior to recalculating the
  31514.  /* default viewing transform for the picture.  Wait for subsequent WM_PAINT
  31515.  /* to do any drawing.
  31516.  /****************************************************************************
  31517.  MRESULT
  31518.  WndProcSize( mp1, mp2)
  31519.  
  31520.  MPARAM        mp1, mp2;
  31521.  {
  31522.    HWND        hwndFrameTemp;
  31523.  
  31524.    if( hwndFrame)
  31525.      hwndFrameTemp = hwndFrame;
  31526.    else
  31527.      hwndFrameTemp = WinQueryWindow( hwndClient, QW_PARENT, FALSE);
  31528.  
  31529.    ptsScrollMax.y = SHORT2FROMMP( mp2);
  31530.    ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
  31531.    if( mp1)
  31532.    {
  31533.        ptsScrollPos.y = (SHORT)(((LONG)ptsScrollPos.y * (LONG)SHORT2FROMMP(mp2
  31534.        ptsOldScrollPos.y = (SHORT)(((LONG)ptsOldScrollPos.y * (LONG)SHORT2FROM
  31535.    } else
  31536.    {
  31537.        ptsScrollPos.y = ptsHalfScrollMax.y;     /* first sizing after window c
  31538.        ptsOldScrollPos.y = ptsHalfScrollMax.y;
  31539.    }
  31540.    WinSendMsg( hwndVertScroll
  31541.              , SBM_SETSCROLLBAR
  31542.              , MPFROMSHORT( ptsScrollPos.y)
  31543.              , MPFROM2SHORT( 1, ptsScrollMax.y) );
  31544.  
  31545.  
  31546.    ptsScrollMax.x = SHORT1FROMMP( mp2);
  31547.    ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
  31548.    if( mp1)
  31549.    {
  31550.        ptsScrollPos.x = (SHORT)(((LONG)ptsScrollPos.x * (LONG)SHORT1FROMMP(mp2
  31551.        ptsOldScrollPos.x = (SHORT)(((LONG)ptsOldScrollPos.x * (LONG)SHORT1FROM
  31552.    } else
  31553.    {
  31554.        ptsScrollPos.x = ptsHalfScrollMax.x;     /* first sizing after window c
  31555.        ptsOldScrollPos.x = ptsHalfScrollMax.x;
  31556.    }
  31557.    WinSendMsg( hwndHorzScroll
  31558.              , SBM_SETSCROLLBAR
  31559.              , MPFROMSHORT( ptsScrollPos.x)
  31560.              , MPFROM2SHORT( 1, ptsScrollMax.x) );
  31561.  
  31562.  
  31563.    SendCommand( UM_SIZING, 0L);
  31564.    return( FALSE);
  31565.  }
  31566.  
  31567.  /****************************************************************************
  31568.  /*
  31569.  /* NewThread is the asynchronous drawing thread. It is responsible for all
  31570.  /* drawing.  It will initialize its PM interface and create an application
  31571.  /* message queue.  It will then monitor its message queue and process any
  31572.  /* commands received.
  31573.  /*
  31574.  /****************************************************************************
  31575.  VOID FAR
  31576.  NewThread()
  31577.  {
  31578.    QMSG          qmsgAsync, qmsgPeek;
  31579.    BOOL          fDone;
  31580.  
  31581.    /**************************************************************************
  31582.    /* Initialize the PM interface.  If it fails, terminate both threads.
  31583.    /**************************************************************************
  31584.    habAsync = WinInitialize( 0);
  31585.    if( !habAsync)
  31586.    {
  31587.        WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
  31588.        DosExit( EXIT_THREAD, 0);
  31589.    }
  31590.  
  31591.    /**************************************************************************
  31592.    /* Create a message queue.  If it fails, terminate both threads.
  31593.    /**************************************************************************
  31594.    hmqAsync = WinCreateMsgQueue( habAsync, 80);
  31595.    if( !hmqAsync)
  31596.    {
  31597.        WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
  31598.        WinTerminate( habAsync);
  31599.        DosExit( EXIT_THREAD, 0);
  31600.    }
  31601.  
  31602.    DosSetPrty( PRTYS_THREAD, PRTYC_NOCHANGE, sPrty, (TID)NULL);
  31603.  
  31604.  
  31605.    while( TRUE)
  31606.    {
  31607.      WinGetMsg( habAsync, &qmsgAsync, NULL, 0, 0);
  31608.  
  31609.      /************************************************************************
  31610.      /* process the commands
  31611.      /************************************************************************
  31612.      switch( qmsgAsync.msg)
  31613.      {
  31614.  
  31615.        /**********************************************************************
  31616.        /**********************************************************************
  31617.        case UM_LOAD:
  31618.          Load( (PLOADINFO)qmsgAsync.mp1);
  31619.          Redraw();
  31620.          break;
  31621.  
  31622.        /**********************************************************************
  31623.        case UM_JUMBLE:
  31624.          Jumble();
  31625.          Redraw();
  31626.          break;
  31627.  
  31628.        /**********************************************************************
  31629.        case UM_REDRAW:
  31630.          Redraw();
  31631.          break;
  31632.  
  31633.        /**********************************************************************
  31634.        /* DRAW will use the passed region containing the invalidated area of
  31635.        /* the screen, repaint it and then destroy the region.
  31636.        /**********************************************************************
  31637.        case UM_DRAW:
  31638.          DoDraw( (HRGN)qmsgAsync.mp1);
  31639.          if( qmsgAsync.mp1)
  31640.              GpiDestroyRegion( hpsClient, (HRGN)qmsgAsync.mp1);
  31641.          break;
  31642.  
  31643.  
  31644.        /**********************************************************************
  31645.        /* Get new scroll posn from command ( i.e. +/-1 +/-page) or new
  31646.        /* absolute position from parameter, update scroll posn, change the
  31647.        /* transform and update the thumb posn.  Finally update the window.
  31648.        /**********************************************************************
  31649.        case UM_HSCROLL:
  31650.          switch( SHORT2FROMMP( qmsgAsync.mp1) )
  31651.          {
  31652.              case SB_LINEUP:
  31653.                  ptsScrollPos.x -= ptsScrollLine.x;
  31654.                  break;
  31655.              case SB_LINEDOWN:
  31656.                  ptsScrollPos.x += ptsScrollLine.x;
  31657.                  break;
  31658.              case SB_SLIDERTRACK:
  31659.              case SB_SLIDERPOSITION:
  31660.                  for( fDone = FALSE; !fDone ;)
  31661.                  {
  31662.                    if( WinPeekMsg( habAsync
  31663.                                  , &qmsgPeek
  31664.                                  , NULL
  31665.                                  , UM_HSCROLL
  31666.                                  , UM_HSCROLL
  31667.                                  , PM_NOREMOVE))
  31668.                        if(   (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
  31669.                            ||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION
  31670.                            WinPeekMsg( habAsync
  31671.                                      , &qmsgAsync
  31672.                                      , NULL
  31673.                                      , UM_HSCROLL
  31674.                                      , UM_HSCROLL
  31675.                                      , PM_REMOVE);
  31676.                        else
  31677.                            fDone = TRUE;
  31678.                    else
  31679.                        fDone = TRUE;
  31680.                  }
  31681.                  ptsScrollPos.x = SHORT1FROMMP( qmsgAsync.mp1);
  31682.                  break;
  31683.              case SB_PAGEUP:
  31684.                  ptsScrollPos.x -= ptsScrollPage.x;
  31685.                  break;
  31686.              case SB_PAGEDOWN:
  31687.                  ptsScrollPos.x += ptsScrollPage.x;
  31688.                  break;
  31689.              case SB_ENDSCROLL:
  31690.                  break;
  31691.              default:
  31692.                  break;
  31693.          }
  31694.          DoHorzScroll();
  31695.          break;
  31696.  
  31697.        case UM_VSCROLL:
  31698.          switch( SHORT2FROMMP( qmsgAsync.mp1) )
  31699.          {
  31700.              case SB_LINEUP:
  31701.                  ptsScrollPos.y -= ptsScrollLine.y;
  31702.                  break;
  31703.              case SB_LINEDOWN:
  31704.                  ptsScrollPos.y += ptsScrollLine.y;
  31705.                  break;
  31706.              case SB_SLIDERTRACK:
  31707.              case SB_SLIDERPOSITION:
  31708.                  for( fDone = FALSE; !fDone ;)
  31709.                  {
  31710.                    if( WinPeekMsg( habAsync
  31711.                                  , &qmsgPeek
  31712.                                  , NULL
  31713.                                  , UM_VSCROLL
  31714.                                  , UM_VSCROLL
  31715.                                  , PM_NOREMOVE))
  31716.                        if(   (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
  31717.                            ||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION
  31718.                            WinPeekMsg( habAsync
  31719.                                      , &qmsgAsync
  31720.                                      , NULL
  31721.                                      , UM_VSCROLL
  31722.                                      , UM_VSCROLL
  31723.                                      , PM_REMOVE);
  31724.                        else
  31725.                            fDone = TRUE;
  31726.                    else
  31727.                        fDone = TRUE;
  31728.                  }
  31729.                  ptsScrollPos.y = SHORT1FROMMP( qmsgAsync.mp1);
  31730.                  break;
  31731.              case SB_PAGEUP:
  31732.                  ptsScrollPos.y -= ptsScrollPage.y;
  31733.                  break;
  31734.              case SB_PAGEDOWN:
  31735.                  ptsScrollPos.y += ptsScrollPage.y;
  31736.                  break;
  31737.              case SB_ENDSCROLL:
  31738.                  break;
  31739.              default:
  31740.                  break;
  31741.          }
  31742.          DoVertScroll();
  31743.          break;
  31744.  
  31745.        /**********************************************************************
  31746.        /* recalc the picture transform
  31747.        /**********************************************************************
  31748.        case UM_SIZING:
  31749.          CalcBounds();
  31750.          CalcTransform( hwndClient);
  31751.          break;
  31752.  
  31753.        /**********************************************************************
  31754.        /* adjust zoom factor
  31755.        /**********************************************************************
  31756.        case UM_ZOOM_IN:
  31757.          Zoom( ZOOM_IN_ARG);
  31758.          break;
  31759.  
  31760.        case UM_ZOOM_OUT:
  31761.          Zoom( ZOOM_OUT_ARG);
  31762.          break;
  31763.  
  31764.        /**********************************************************************
  31765.        /* toggle fast-drag
  31766.        /**********************************************************************
  31767.        case UM_FASTDRAG:
  31768.          ToggleFastDrag();
  31769.          break;
  31770.  
  31771.        /**********************************************************************
  31772.        /* Button down will cause a correlate on the picture to test for a hit.
  31773.        /* Any selected segment will be highlighted and redrawn as dynamic.
  31774.        /**********************************************************************
  31775.        case UM_LEFTDOWN:
  31776.          LeftDown( qmsgAsync.mp1);
  31777.          break;
  31778.  
  31779.        /**********************************************************************
  31780.        /* if a segment is being dragged it will be redrawn in a new posn
  31781.        /**********************************************************************
  31782.        case UM_MOUSEMOVE:
  31783.          for( fDone = FALSE; !fDone ;)
  31784.          {
  31785.            if( WinPeekMsg( habAsync
  31786.                          , &qmsgPeek
  31787.                          , NULL
  31788.                          , UM_MOUSEMOVE
  31789.                          , UM_LEFTUP
  31790.                          , PM_NOREMOVE))
  31791.                if( qmsgPeek.msg == UM_MOUSEMOVE)
  31792.                    WinPeekMsg( habAsync
  31793.                              , &qmsgAsync
  31794.                              , NULL
  31795.                              , UM_MOUSEMOVE
  31796.                              , UM_MOUSEMOVE
  31797.                              , PM_REMOVE);
  31798.                else
  31799.                    fDone = TRUE;
  31800.            else
  31801.                fDone = TRUE;
  31802.          }
  31803.          MouseMove( qmsgAsync.mp1);
  31804.          break;
  31805.  
  31806.        /**********************************************************************
  31807.        /* if a segment is being dragged it will be redrawn as normal
  31808.        /**********************************************************************
  31809.        case UM_LEFTUP:
  31810.          LeftUp();
  31811.          break;
  31812.  
  31813.        /**********************************************************************
  31814.        /* destroy resources and terminate
  31815.        /**********************************************************************
  31816.        case UM_DIE:
  31817.          WinDestroyMsgQueue( hmqAsync);
  31818.          WinTerminate( habAsync);
  31819.          DosEnterCritSec();
  31820.          DosSemClear( hsemTerminate);
  31821.          DosExit( EXIT_THREAD, 0);
  31822.          break;
  31823.  
  31824.        /**********************************************************************
  31825.        /* finish flush of commands from queue
  31826.        /**********************************************************************
  31827.        case UM_FLUSH:
  31828.          break;
  31829.  
  31830.        default:
  31831.          break;
  31832.      }
  31833.    }
  31834.  }
  31835.  
  31836.  /****************************************************************************
  31837.  /* button down will cause one segment to be indicated and made dynamic
  31838.  /****************************************************************************
  31839.  VOID
  31840.  LeftDown( mp)
  31841.  
  31842.  MPARAM         mp;
  31843.  {
  31844.    HRGN            hrgnUpdt;
  31845.    LONG            alSegTag[HITS][DEPTH][2];
  31846.    POINTL    ptl, aptl[4];
  31847.    RECTL     rcl;
  31848.    MATRIXLF  matlf;
  31849.    LONG            lOffset;
  31850.    BYTE            bBuff[128];
  31851.    CHAR            pszMsg[40];
  31852.    PSZ            psz1, psz2;
  31853.  
  31854.    ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
  31855.    ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
  31856.  
  31857.    /**************************************************************************
  31858.    /**************************************************************************
  31859.    for( pslPicked = pslTail; pslPicked != NULL; pslPicked = pslPicked->pslPrev
  31860.    {
  31861.      rcl = pslPicked->rclCurrent;
  31862.      GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 2L, (PPOINTL)&rcl);
  31863.      rcl.xRight++;
  31864.      rcl.yTop++;
  31865.      if( WinPtInRect( habAsync, &rcl, &ptl))
  31866.      {
  31867.          LONG lRet;
  31868.  
  31869.          GpiSetEditMode( hpsClient, SEGEM_INSERT);
  31870.          GpiOpenSegment( hpsClient, pslPicked->lSegId);
  31871.          GpiSetElementPointerAtLabel( hpsClient, FILLPATH);
  31872.          GpiFillPath( hpsClient, 1L, 0L);
  31873.          GpiCloseSegment( hpsClient);
  31874.          lRet = GpiCorrelateSegment( hpsClient
  31875.                                    , pslPicked->lSegId
  31876.                                    , PICKSEL_VISIBLE
  31877.                                    , &ptl
  31878.                                    , HITS
  31879.                                    , DEPTH
  31880.                                    , (PLONG)alSegTag );
  31881.          GpiOpenSegment( hpsClient, pslPicked->lSegId);
  31882.          GpiSetElementPointerAtLabel( hpsClient, FILLPATH);
  31883.          GpiOffsetElementPointer( hpsClient, 1L);
  31884.          GpiDeleteElement( hpsClient);
  31885.          GpiCloseSegment( hpsClient);
  31886.  
  31887.          if( lRet > 0)
  31888.              break;
  31889.      }
  31890.    }
  31891.    if( pslPicked)
  31892.      lPickedSeg         = pslPicked->lSegId;
  31893.    else
  31894.    {
  31895.      fButtonDown = FALSE;
  31896.      return;
  31897.    }
  31898.    if( (lPickedSeg < 1) || (lPickedSeg > lLastSegId) )
  31899.    {
  31900.      DosSemRequest( hsemSzFmt, SEM_INDEFINITE_WAIT);
  31901.      sprintf( szFmt, "Segment id out of range: %x", lPickedSeg);
  31902.      for( psz1 = szFmt, psz2 = pszMsg; *psz2++ = *psz1++; )
  31903.          ;
  31904.      DosSemClear( hsemSzFmt);
  31905.      MyMessageBox( hwndClient, pszMsg);
  31906.      fButtonDown = FALSE;
  31907.      return;
  31908.    }
  31909.  
  31910.    /**************************************************************************
  31911.    hrgnUpdt = GpiCreateRegion( hpsClient, 1L, &rcl);
  31912.    GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_VISIBLE, ATTR_OFF);
  31913.  
  31914.    GpiQuerySegmentTransformMatrix( hpsClient
  31915.                                  , lPickedSeg
  31916.                                  , 9L
  31917.                                  , &matlf );
  31918.    GpiBeginPath( hpsClient, 1L);
  31919.    GpiCallSegmentMatrix( hpsClient
  31920.                        , lPickedSeg + CALLSEG_BASE
  31921.                        , 9L
  31922.                        , &matlf
  31923.                        , TRANSFORM_REPLACE );
  31924.    GpiEndPath( hpsClient);
  31925.    GpiSetClipPath( hpsClient, 1L, SCP_AND);
  31926.    DoDraw( hrgnUpdt);
  31927.    GpiSetClipPath( hpsClient, 0L, SCP_RESET);
  31928.    GpiDestroyRegion( hpsClient, hrgnUpdt);
  31929.  
  31930.    /**************************************************************************
  31931.    ptlOffset = ptlBotLeft;
  31932.    GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 1L, &ptlOffset);
  31933.  
  31934.    aptl[0].x = pslPicked->rclBitBlt.xLeft;
  31935.    aptl[0].y = pslPicked->rclBitBlt.yBottom;
  31936.    aptl[1].x = pslPicked->rclBitBlt.xRight;
  31937.    aptl[1].y = pslPicked->rclBitBlt.yTop;
  31938.    aptl[2] = aptl[0];
  31939.    aptl[3] = aptl[1];
  31940.    GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, &aptl[2]);
  31941.    aptl[2].x -= ptlOffset.x;
  31942.    aptl[2].y -= ptlOffset.y;
  31943.    aptl[3].x -= ptlOffset.x - 1;
  31944.    aptl[3].y -= ptlOffset.y - 1;
  31945.    GpiSetEditMode( hpsClient, SEGEM_INSERT);
  31946.  
  31947.    for( lOffset = 0L; GpiGetData( hpsClient
  31948.                                 , lPickedSeg
  31949.                                 , &lOffset
  31950.                                 , DFORM_NOCONV
  31951.                                 , (LONG)sizeof( bBuff)
  31952.                                 , bBuff) > 0; )
  31953.        ;
  31954.  
  31955.    GpiOpenSegment( hpsClient, lPickedSeg);
  31956.    GpiDeleteElementsBetweenLabels( hpsClient, BITBLT_TOP, BITBLT_BOTTOM);
  31957.    if( !fFastDrag)
  31958.        GpiWCBitBlt( hpsClient
  31959.                   , hbmBitmapDrag
  31960.                   , 4L
  31961.                   , aptl
  31962.                   , ROP_SRCCOPY
  31963.                   , BBO_IGNORE );
  31964.    GpiCloseSegment( hpsClient);
  31965.  
  31966.    for( lOffset = 0L; GpiGetData( hpsClient
  31967.                                 , lPickedSeg
  31968.                                 , &lOffset
  31969.                                 , DFORM_NOCONV
  31970.                                 , (LONG)sizeof( bBuff)
  31971.                                 , bBuff) > 0; )
  31972.        ;
  31973.  
  31974.    /**************************************************************************
  31975.    GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_VISIBLE, ATTR_ON);
  31976.    GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_DYNAMIC, ATTR_ON);
  31977.    GpiSetDrawControl( hpsClient, DCTL_DYNAMIC, DCTL_ON);
  31978.    GpiDrawSegment( hpsClient, lPickedSeg);
  31979.  
  31980.    WinSetCapture( HWND_DESKTOP, hwndClient);
  31981.  }
  31982.  
  31983.  
  31984.  
  31985.  
  31986.  /****************************************************************************
  31987.  /*
  31988.  /* move the segment
  31989.  /*
  31990.  /****************************************************************************
  31991.  VOID
  31992.  MouseMove( mp)
  31993.  
  31994.  MPARAM         mp;
  31995.  {
  31996.    RECTL   rcl;
  31997.    POINTL  ptl, ptlModel;
  31998.  
  31999.    ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
  32000.    ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
  32001.  
  32002.    ptlModel = ptl;
  32003.    GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptlModel);
  32004.    ptlModel.x = 5 * (ptlModel.x / 5);
  32005.    ptlModel.y = 5 * (ptlModel.y / 5);
  32006.    if( (ptlModel.x == ptlOldMouse.x) && (ptlModel.y == ptlOldMouse.y))
  32007.      return;
  32008.    ptlOldMouse.x = ptlModel.x;
  32009.    ptlOldMouse.y = ptlModel.y;
  32010.  
  32011.    /**************************************************************************
  32012.    /* clip mouse coords to client window
  32013.    /**************************************************************************
  32014.    WinQueryWindowRect(hwndClient, &rcl);
  32015.    if (rcl.xLeft > ptl.x)
  32016.      ptl.x = rcl.xLeft;
  32017.    if (rcl.xRight <= ptl.x)
  32018.      ptl.x = rcl.xRight;
  32019.    if (rcl.yBottom > ptl.y)
  32020.      ptl.y = rcl.yBottom;
  32021.    if (rcl.yTop <= ptl.y)
  32022.      ptl.y = rcl.yTop;
  32023.  
  32024.    GpiRemoveDynamics( hpsClient, lPickedSeg, lPickedSeg);
  32025.    Translate( pslPicked, &ptl);
  32026.    GpiDrawDynamics( hpsClient);
  32027.  }
  32028.  
  32029.  
  32030.  /****************************************************************************
  32031.  /*
  32032.  /* The dragged segment is being unselected.  Return it to its normal state.
  32033.  /*
  32034.  /****************************************************************************
  32035.  VOID
  32036.  LeftUp()
  32037.  {
  32038.    SEGLIST    sl;
  32039.    POINTL     aptl[4];
  32040.  
  32041.    if( !lPickedSeg)
  32042.      return;
  32043.    GpiRemoveDynamics( hpsClient, lPickedSeg, lPickedSeg);
  32044.    GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_DYNAMIC, ATTR_OFF);
  32045.  
  32046.    /**************************************************************************
  32047.    ptlOffset = ptlBotLeft;
  32048.    GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 1L, &ptlOffset);
  32049.  
  32050.    aptl[0].x = pslPicked->rclBitBlt.xLeft;
  32051.    aptl[0].y = pslPicked->rclBitBlt.yBottom;
  32052.    aptl[1].x = pslPicked->rclBitBlt.xRight;
  32053.    aptl[1].y = pslPicked->rclBitBlt.yTop;
  32054.    aptl[2] = aptl[0];
  32055.    aptl[3] = aptl[1];
  32056.    GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, &aptl[2]);
  32057.    aptl[2].x -= ptlOffset.x;
  32058.    aptl[2].y -= ptlOffset.y;
  32059.    aptl[3].x -= ptlOffset.x - 1;
  32060.    aptl[3].y -= ptlOffset.y - 1;
  32061.    GpiSetEditMode( hpsClient, SEGEM_INSERT);
  32062.    GpiOpenSegment( hpsClient, lPickedSeg);
  32063.    GpiDeleteElementsBetweenLabels( hpsClient, BITBLT_TOP, BITBLT_BOTTOM);
  32064.    GpiWCBitBlt( hpsClient
  32065.               , hbmBitmapTemp
  32066.               , 4L
  32067.               , aptl
  32068.               , ROP_SRCCOPY
  32069.               , BBO_IGNORE );
  32070.    GpiCloseSegment( hpsClient);
  32071.  
  32072.    /**************************************************************************
  32073.    GpiDrawSegment( hpsClient, lPickedSeg);
  32074.    GpiSetSegmentPriority( hpsClient, lPickedSeg, 0L, LOWER_PRI); /* highest
  32075.    SetRect( pslPicked);
  32076.  
  32077.    sl = *pslPicked;
  32078.    SegListUpdate( DEL_SEG, pslPicked);
  32079.    SegListUpdate( ADD_TAIL_SEG, &sl);            /* at tail => highest priorit
  32080.    pslPicked = NULL;
  32081.  
  32082.    WinSetCapture( HWND_DESKTOP, (HWND)NULL);
  32083.  }
  32084.  
  32085.  
  32086.  /****************************************************************************
  32087.  /*
  32088.  /* DoHorzScroll will horizontally scroll the current contents of
  32089.  /* the client area and redraw the invalidated area
  32090.  /*
  32091.  /****************************************************************************
  32092.  VOID
  32093.  DoHorzScroll()
  32094.  {
  32095.    RECTL     rcl;
  32096.    HRGN            hrgn;
  32097.    MATRIXLF  matlf;
  32098.  
  32099.    if( ptsScrollPos.x > ptsScrollMax.x)
  32100.        ptsScrollPos.x = ptsScrollMax.x;
  32101.    if( ptsScrollPos.x < 0)
  32102.        ptsScrollPos.x = 0;
  32103.  
  32104.    if( ptsOldScrollPos.x != ptsScrollPos.x)
  32105.        WinSendMsg( hwndHorzScroll
  32106.                  , SBM_SETPOS
  32107.                  , MPFROM2SHORT( ptsScrollPos.x, 0)
  32108.                  , MPFROMLONG( NULL));
  32109.  
  32110.    /**************************************************************************
  32111.    /* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow)
  32112.    /* if any of the screen still in view, and paint into uncovered region;
  32113.    /* else repaint the whole client area.
  32114.    /**************************************************************************
  32115.    hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
  32116.    if( abs( ptsScrollPos.x - ptsOldScrollPos.x) <= ptsScrollMax.x)
  32117.    {
  32118.        WinScrollWindow( hwndClient
  32119.                       , ptsOldScrollPos.x - ptsScrollPos.x
  32120.                       , 0
  32121.                       , NULL
  32122.                       , NULL
  32123.                       , hrgn
  32124.                       , &rcl
  32125.                       , 0);
  32126.    } else
  32127.    {
  32128.        WinQueryWindowRect( hwndClient, &rcl);
  32129.        GpiSetRegion( hpsClient, hrgn, 1L, &rcl);
  32130.    }
  32131.    GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf );
  32132.    matlf.lM31 -= ptsScrollPos.x - ptsOldScrollPos.x;
  32133.    GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE);
  32134.  
  32135.    DoDraw( hrgn);
  32136.    ptsOldScrollPos.x = ptsScrollPos.x;
  32137.    GpiDestroyRegion( hpsClient, hrgn);
  32138.  }
  32139.  
  32140.  /****************************************************************************
  32141.  /*
  32142.  /* DoVertScroll will vertically scroll the current contents of
  32143.  /* the client area and redraw the invalidated area
  32144.  /*
  32145.  /****************************************************************************
  32146.  VOID
  32147.  DoVertScroll()
  32148.  {
  32149.    RECTL     rcl;
  32150.    HRGN            hrgn;
  32151.    MATRIXLF  matlf;
  32152.  
  32153.    if( ptsScrollPos.y > ptsScrollMax.y)
  32154.        ptsScrollPos.y = ptsScrollMax.y;
  32155.    if( ptsScrollPos.y < 0)
  32156.        ptsScrollPos.y = 0;
  32157.  
  32158.    if( ptsOldScrollPos.y != ptsScrollPos.y)
  32159.        WinSendMsg( hwndVertScroll
  32160.                  , SBM_SETPOS
  32161.                  , MPFROM2SHORT( ptsScrollPos.y, 0)
  32162.                  , MPFROMLONG( NULL));
  32163.  
  32164.    /**************************************************************************
  32165.    /* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow)
  32166.    /* if any of the screen still in view, and paint into uncovered region;
  32167.    /* else repaint the whole client area.
  32168.    /**************************************************************************
  32169.    hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
  32170.    if( abs( ptsScrollPos.y - ptsOldScrollPos.y) <= ptsScrollMax.y)
  32171.    {
  32172.        WinScrollWindow( hwndClient
  32173.                       , 0
  32174.                       , ptsScrollPos.y - ptsOldScrollPos.y
  32175.                       , NULL
  32176.                       , NULL
  32177.                       , hrgn
  32178.                       , &rcl
  32179.                       , 0);
  32180.    } else
  32181.    {
  32182.        WinQueryWindowRect( hwndClient, &rcl);
  32183.        GpiSetRegion( hpsClient, hrgn, 1L, &rcl);
  32184.    }
  32185.    GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf );
  32186.    matlf.lM32 += ptsScrollPos.y - ptsOldScrollPos.y;
  32187.    GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE);
  32188.  
  32189.    DoDraw( hrgn);
  32190.    ptsOldScrollPos.y = ptsScrollPos.y;
  32191.    GpiDestroyRegion( hpsClient, hrgn);
  32192.  }
  32193.  
  32194.  /****************************************************************************
  32195.  /*
  32196.  /* Redraw the entire client window.
  32197.  /*
  32198.  /****************************************************************************
  32199.  VOID
  32200.  Redraw()
  32201.  {
  32202.    RECTL   rclInvalid;
  32203.    HRGN          hrgnUpdt;
  32204.  
  32205.    WinQueryWindowRect( hwndClient, &rclInvalid);
  32206.    hrgnUpdt = GpiCreateRegion( hpsClient, 1L, &rclInvalid);
  32207.    DoDraw( hrgnUpdt);
  32208.    GpiDestroyRegion( hpsClient, hrgnUpdt);
  32209.  }
  32210.  
  32211.  
  32212.  /****************************************************************************
  32213.  /*
  32214.  /* toggle the fast-drag flag and update the menu check-box
  32215.  /*
  32216.  /****************************************************************************
  32217.  VOID
  32218.  ToggleFastDrag()
  32219.  {
  32220.    MENUITEM mi;
  32221.    HWND           hwndMenu, hwndOptions;
  32222.  
  32223.    hwndMenu = WinWindowFromID( hwndFrame, FID_MENU);
  32224.    WinSendMsg( hwndMenu
  32225.              , MM_QUERYITEM
  32226.              , MPFROM2SHORT( SM_OPTIONS, FALSE)
  32227.              , MPFROMP( (PMENUITEM)&mi));
  32228.    hwndOptions = mi.hwndSubMenu;
  32229.  
  32230.    if( fFastDrag)
  32231.    {
  32232.      fFastDrag = FALSE;
  32233.      WinSendMsg( hwndOptions
  32234.                , MM_SETITEMATTR
  32235.                , MPFROM2SHORT( MENU_FASTDRAG, TRUE)
  32236.                , MPFROM2SHORT( MIA_CHECKED, ~MIA_CHECKED) );
  32237.    }
  32238.    else
  32239.    {
  32240.      fFastDrag = TRUE;
  32241.      WinSendMsg( hwndOptions
  32242.                , MM_SETITEMATTR
  32243.                , MPFROM2SHORT( MENU_FASTDRAG, TRUE)
  32244.                , MPFROM2SHORT( MIA_CHECKED, MIA_CHECKED) );
  32245.    }
  32246.  }
  32247.  
  32248.  /****************************************************************************
  32249.  /*
  32250.  /* adjust zoom factor and recalc the picture transform, then do a redraw of
  32251.  /* whole screen
  32252.  /*
  32253.  /****************************************************************************
  32254.  VOID
  32255.  Zoom( sInOrOut)
  32256.  
  32257.  SHORT sInOrOut;
  32258.  {
  32259.    LONG         lScaleOld;
  32260.  
  32261.    lScaleOld = lScale;
  32262.    lScale += sInOrOut;
  32263.    if( lScale > ZOOM_MAX)
  32264.      lScale = ZOOM_MAX;
  32265.    else
  32266.      if( lScale < -ZOOM_MAX)
  32267.        lScale = -ZOOM_MAX;
  32268.    if( lScale != lScaleOld)
  32269.    {
  32270.        ZoomMenuItems();
  32271.        CalcBounds();
  32272.        CalcTransform( hwndClient);
  32273.        Redraw();
  32274.    }
  32275.  }
  32276.  
  32277.  /****************************************************************************
  32278.  /*
  32279.  /* enable/disable zoom menu items depending on scaling
  32280.  /*
  32281.  /****************************************************************************
  32282.  VOID
  32283.  ZoomMenuItems()
  32284.  {
  32285.    MENUITEM  mi;
  32286.    HWND            hwndMenu, hwndOptions;
  32287.  
  32288.    hwndMenu = WinWindowFromID( hwndFrame, FID_MENU);
  32289.    WinSendMsg( hwndMenu
  32290.              , MM_QUERYITEM
  32291.              , MPFROM2SHORT( SM_OPTIONS, FALSE)
  32292.              , MPFROMP( (PMENUITEM)&mi));
  32293.    hwndOptions = mi.hwndSubMenu;
  32294.  
  32295.    if( lScale >= ZOOM_MAX)
  32296.    {
  32297.        WinSendMsg( hwndOptions
  32298.                  , MM_SETITEMATTR
  32299.                  , MPFROM2SHORT( MENU_ZOOMIN, TRUE)
  32300.                  , MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED));
  32301.        WinSendMsg( hwndOptions
  32302.                  , MM_SETITEMATTR
  32303.                  , MPFROM2SHORT( MENU_ZOOMOUT, TRUE)
  32304.                  , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
  32305.    } else
  32306.    {
  32307.        if( lScale <= - ZOOM_MAX)
  32308.        {
  32309.            WinSendMsg( hwndOptions
  32310.                      , MM_SETITEMATTR
  32311.                      , MPFROM2SHORT( MENU_ZOOMOUT, TRUE)
  32312.                      , MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED));
  32313.            WinSendMsg( hwndOptions
  32314.                      , MM_SETITEMATTR
  32315.                      , MPFROM2SHORT( MENU_ZOOMIN, TRUE)
  32316.                      , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
  32317.        } else
  32318.        {
  32319.            WinSendMsg( hwndOptions
  32320.                      , MM_SETITEMATTR
  32321.                      , MPFROM2SHORT( MENU_ZOOMOUT, TRUE)
  32322.                      , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
  32323.            WinSendMsg( hwndOptions
  32324.                      , MM_SETITEMATTR
  32325.                      , MPFROM2SHORT( MENU_ZOOMIN, TRUE)
  32326.                      , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
  32327.        }
  32328.    }
  32329.  }
  32330.  
  32331.  /****************************************************************************
  32332.  /*
  32333.  /* Determine the bounding rect of a segment.
  32334.  /*
  32335.  /****************************************************************************
  32336.  VOID
  32337.  SetRect( psl)
  32338.  
  32339.  PSEGLIST  psl;
  32340.  {
  32341.    GpiResetBoundaryData( hpsClient);
  32342.    GpiSetDrawControl( hpsClient, DCTL_DISPLAY, DCTL_OFF);
  32343.    GpiSetDrawControl( hpsClient, DCTL_BOUNDARY, DCTL_ON);
  32344.    GpiDrawSegment( hpsClient, psl->lSegId);
  32345.    GpiSetDrawControl( hpsClient, DCTL_DISPLAY, DCTL_ON);
  32346.    GpiSetDrawControl( hpsClient, DCTL_BOUNDARY, DCTL_OFF);
  32347.    GpiQueryBoundaryData( hpsClient, &(psl->rclCurrent));
  32348.  }
  32349.  
  32350.  /****************************************************************************
  32351.  /*
  32352.  /* Translate a segment
  32353.  /*
  32354.  /****************************************************************************
  32355.  VOID
  32356.  Translate( psl, pptlNew)
  32357.  
  32358.  PSEGLIST  psl;
  32359.  PPOINTL   pptlNew;
  32360.  {
  32361.    POINTL    ptl;
  32362.    MATRIXLF  matlf;
  32363.  
  32364.    ptl = *pptlNew;
  32365.    GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptl);
  32366.    ptl.x = (ptl.x / 5) * 5;
  32367.    ptl.y = (ptl.y / 5) * 5;
  32368.    ptl.x -= 25;
  32369.    ptl.y -= 25;
  32370.  
  32371.    GpiQuerySegmentTransformMatrix( hpsClient
  32372.                                  , psl->lSegId
  32373.                                  , 9L
  32374.                                  , &matlf);
  32375.    matlf.lM31 = ptl.x - (psl->ptlLocation).x;
  32376.    matlf.lM32 = ptl.y - (psl->ptlLocation).y;
  32377.    GpiSetSegmentTransformMatrix( hpsClient
  32378.                                , psl->lSegId
  32379.                                , 9L
  32380.                                , &matlf
  32381.                                , TRANSFORM_REPLACE);
  32382.  }
  32383.  
  32384.  
  32385.  /****************************************************************************
  32386.  /*
  32387.  /* set the default viewing transform
  32388.  /*
  32389.  /****************************************************************************
  32390.  VOID
  32391.  SetDVTransform( fx11, fx12, fx21, fx22, l31, l32, lType)
  32392.  
  32393.  FIXED        fx11, fx12, fx21, fx22;
  32394.  LONG        l31, l32, lType;
  32395.  {
  32396.    MATRIXLF  matlf;
  32397.  
  32398.    matlf.fxM11 = fx11;
  32399.    matlf.fxM12 = fx12;
  32400.    matlf.lM13  = 0L;
  32401.    matlf.fxM21 = fx21;
  32402.    matlf.fxM22 = fx22;
  32403.    matlf.lM23  = 0L;
  32404.    matlf.lM31  = l31;
  32405.    matlf.lM32  = l32;
  32406.    matlf.lM33  = 1L;
  32407.    GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, lType);
  32408.  }
  32409.  
  32410.  /****************************************************************************
  32411.  /*
  32412.  /* get bounding rect of whole picture in model coordinates
  32413.  /*
  32414.  /****************************************************************************
  32415.  VOID
  32416.  CalcBounds()
  32417.  {
  32418.    PSEGLIST  psl;
  32419.    RECTL     rcl;
  32420.  
  32421.    if( !pslHead)
  32422.      return;
  32423.    rclBounds = pslHead->rclCurrent;
  32424.    for( psl = pslHead->pslNext; psl != NULL; psl = psl->pslNext)
  32425.    {
  32426.      rcl = psl->rclCurrent;
  32427.      if( rcl.xLeft < rclBounds.xLeft)
  32428.        rclBounds.xLeft = rcl.xLeft;
  32429.      if( rcl.xRight > rclBounds.xRight)
  32430.        rclBounds.xRight = rcl.xRight;
  32431.      if( rcl.yTop > rclBounds.yTop)
  32432.        rclBounds.yTop = rcl.yTop;
  32433.      if( rcl.yBottom < rclBounds.yBottom)
  32434.        rclBounds.yBottom = rcl.yBottom;
  32435.    }
  32436.  }
  32437.  
  32438.  /****************************************************************************
  32439.  /*
  32440.  /* Calculate and set the default viewing transform based on zoom and scroll
  32441.  /*
  32442.  /****************************************************************************
  32443.  VOID
  32444.  CalcTransform( hwnd)
  32445.  
  32446.  HWND hwnd;
  32447.  {
  32448.    RECTL     rclClient;
  32449.    POINTL    ptlCenter, ptlTrans, ptlScale, aptl[4];
  32450.    HRGN            hrgn;
  32451.    PSEGLIST  psl;
  32452.  
  32453.    /**************************************************************************
  32454.    /* from bounding rect of picture get center of picture
  32455.    /**************************************************************************
  32456.    ptlCenter.x = (rclBounds.xLeft   + rclBounds.xRight) / 2;
  32457.    ptlCenter.y = (rclBounds.yBottom + rclBounds.yTop  ) / 2;
  32458.  
  32459.    /**************************************************************************
  32460.    /* translate center of picture to origin
  32461.    /**************************************************************************
  32462.    SetDVTransform( (FIXED)UNITY
  32463.                  , (FIXED)0
  32464.                  , (FIXED)0
  32465.                  , (FIXED)UNITY
  32466.                  , -ptlCenter.x
  32467.                  , -ptlCenter.y
  32468.                  , TRANSFORM_REPLACE);
  32469.  
  32470.    /**************************************************************************
  32471.    /* scale down to 60% of max client area
  32472.    /**************************************************************************
  32473.    ptlScale.x = (6 * UNITY * sizlMaxClient.cx) /
  32474.                 (10 * (ptlTopRight.x - ptlBotLeft.x));
  32475.    ptlScale.y = (6 * UNITY * sizlMaxClient.cy) /
  32476.                 (10 * (ptlTopRight.y - ptlBotLeft.y));
  32477.  
  32478.    /******************