home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / SAMPLES / PENPAD / PENPAD.C_ / PENPAD.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  39.0 KB  |  1,157 lines

  1. /***************************************************************************
  2.  *                                     *
  3.  *  PROGRAM : penpad.c                         *
  4.  *                                     *
  5.  *  PURPOSE : To give a demonstration of the easy modification of an   *
  6.  *        existing multi-pad application to be pen-aware.  The only*
  7.  *        difference between this code and the original            *
  8.  *        (PENPAD.OLD) is a subclassed window procedure called     *
  9.  *        FakeProc.                        *
  10.  *                                                                *
  11.  *        PenWin must be present to run this application            *
  12.  *                                     *
  13.  *  FUNCTIONS   : WinMain()       - Calls the initialization function  *
  14.  *                  and processes message loop     *
  15.  *                                     *
  16.  *        PPFrameWndProc()    - Window function for the "frame"    *
  17.  *                  window, which controls the menu    *
  18.  *                  and contains the MDI document      *
  19.  *                  windows as child windows.      *
  20.  *                                     *
  21.  *        PPMDIChildWndProc() - Window function for the individual *
  22.  *                  document windows           *
  23.  *                                     *
  24.  *        InitializeMenu()    - Handles enabling/greying of menu   *
  25.  *                  items according to the app's state.*
  26.  *                                     *
  27.  *        CloseAllChildren    - Destroys all MDI child windows.    *
  28.  *                                     *
  29.  *        CommandHandler()    - Processes the "frame" window's     *
  30.  *                  WM_COMMAND messages.           *
  31.  *                                     *
  32.  *        AboutDlgProc()      - Dialog function for the ubiquitous *
  33.  *                  About.. dialog.            *
  34.  *                                     *
  35.  *        SetWrap()       - Alters word wrapping in the edit   *
  36.  *                  control.               *
  37.  *                                     *
  38.  *        PPError()       - Flashes an error messagebox.       *
  39.  *                                     *
  40.  *        QueryCloseChild     - Prompts for saving current MDI     *
  41.  *                  child window.              *
  42.  *                                     *
  43.  *        QueryCloseAllChildren() - Asks whether it is OK to close *
  44.  *                      down app.              *
  45.  *                                     *
  46.  *        FakeProc()          - Subclassed window procedure to     *
  47.  *                  support pens.              *
  48.  *                                     *
  49.  ***************************************************************************/
  50.  
  51. #include "penpad.h"
  52. #define NOPENINFO
  53. #define NOVIRTEVENT
  54. #define NORCDICTIONARY
  55. #define NOCONFIGRECOG
  56. #include <penwin.h>
  57.  
  58. /* global variables used in this module or among more than one module */
  59. FARPROC lpfnFakeProc;           /* Subclassed window procedure           */
  60. FARPROC lpfnEditProc;           /* Edit control procedure used during    */
  61.                     /*  subclassing              */
  62. HANDLE hInst;               /* Program instance handle           */
  63. HANDLE hAccel;              /* Main accelerator resource         */
  64. HWND hwndFrame       = NULL;    /* Handle to main window             */
  65. HWND hwndMDIClient   = NULL;    /* Handle to MDI client          */
  66. HWND hwndActive      = NULL;    /* Handle to currently activated child   */
  67. HWND hwndActiveEdit  = NULL;    /* Handle to edit control            */
  68. LONG styleDefault    = WS_MAXIMIZE; /* Default style bits for child windows  */
  69.                     /* The first window is created maximized */
  70.                     /* to resemble Notepad.  Later children  */
  71.                     /* are normal windows.           */
  72. LPCSTR lpMenu        = IDPENPAD;  /* Contains the resource id of the         */
  73.                     /* current frame menu            */
  74. HCURSOR hCursor;
  75.  
  76.  
  77. int (FAR PASCAL *lpfnProcessWriting)(HWND, LPRC);
  78. int (FAR PASCAL *lpfnTPtoDP)(LPPOINT, int);
  79.  
  80. /* Forward declarations of helper functions in this module */
  81. int       PASCAL WinMain( HANDLE, HANDLE, LPSTR, int);
  82. VOID NEAR PASCAL InitializeMenu (HANDLE);
  83. VOID NEAR PASCAL CommandHandler (HWND,WORD);
  84. VOID NEAR PASCAL SetWrap (HWND,BOOL);
  85. BOOL NEAR PASCAL QueryCloseAllChildren ( VOID );
  86. int  NEAR PASCAL QueryCloseChild (HWND);
  87. VOID NEAR PASCAL CloseAllChildren ( VOID );
  88. BOOL NEAR PASCAL FCheckForPenWin(VOID);
  89.  
  90. /****************************************************************************
  91.  *                                      *
  92.  *  FUNCTION   : WinMain(HANDLE, HANDLE, LPSTR, int)                *
  93.  *                                      *
  94.  *  PURPOSE    : Creates the "frame" window, does some initialization and   *
  95.  *       enters the message loop.                   *
  96.  *                                      *
  97.  ****************************************************************************/
  98. int PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
  99.  
  100. HANDLE hInstance;
  101. HANDLE hPrevInstance;
  102. LPSTR  lpszCmdLine;
  103. int    nCmdShow;
  104. {
  105.     MSG msg;
  106.  
  107.     hInst = hInstance;
  108.  
  109.     /* If this is the first instance of the app. register window classes */
  110.     if (!hPrevInstance){
  111.     if (!InitializeApplication ())
  112.         return 0;
  113.     }
  114.  
  115.     if (!FCheckForPenWin())
  116.         return 0;
  117.  
  118.     /* Create the frame and do other initialization */
  119.     if (!InitializeInstance (lpszCmdLine, nCmdShow))
  120.         return 0;
  121.  
  122.      /* Load appropriate cursor */ 
  123.     hCursor = LoadCursor(NULL, IDC_PEN );   
  124.  
  125.     /* Enter main message loop */
  126.     while (GetMessage (&msg, NULL, 0, 0)){
  127.     /* If a keyboard message is for the MDI , let the MDI client
  128.      * take care of it.  Otherwise, check to see if it's a normal
  129.      * accelerator key (like F3 = find next).  Otherwise, just handle
  130.      * the message as usual.
  131.      */
  132.     if ( !TranslateMDISysAccel (hwndMDIClient, &msg) &&
  133.          !TranslateAccelerator (hwndFrame, hAccel, &msg)){
  134.         TranslateMessage (&msg);
  135.         DispatchMessage (&msg);
  136.     }
  137.     }
  138.     return 0;
  139. }
  140.  
  141.  
  142.  
  143. /****************************************************************************
  144.  *                                      *
  145.  *  FUNCTION   : FCheckForPenWin()     *
  146.  *                                      *
  147.  *  PURPOSE    : Detect presences of Pen Win.  If not there, will just
  148.  *             : behavior as a normal Win 3.0 applicaiton.
  149.  *
  150.  *  RETURN     : Return false on error. *
  151.  ****************************************************************************/
  152. BOOL NEAR PASCAL FCheckForPenWin()
  153.     {
  154.     BOOL fRet = FALSE;
  155.     HANDLE hLib;
  156.  
  157.     if ( (hLib = GetSystemMetrics(SM_PENWINDOWS)) != NULL)
  158.         {
  159.         /* Load up pen win stubb; */ 
  160.         if ( ((FARPROC)lpfnProcessWriting = GetProcAddress(hLib, "ProcessWriting")) != NULL)
  161.             {
  162.             if ( ((FARPROC)lpfnTPtoDP = GetProcAddress(hLib, "TPtoDP")) != NULL)
  163.                 fRet = TRUE;
  164.             }
  165.  
  166.  
  167.         }
  168.     /* else running on a non pen aware system */
  169.  
  170.     if (!fRet)
  171.         MessageBox(NULL, "This application requires Microsoft Windows for Pen Computing", "PenPad", MB_OK);
  172.  
  173.     return fRet;
  174.     }
  175.  
  176.  
  177.  
  178.  
  179. /****************************************************************************
  180.  *                                      *
  181.  *  FUNCTION   : PPFrameWndProc (hwnd, msg, wParam, lParam )            *
  182.  *                                      *
  183.  *  PURPOSE    : The window function for the "frame" window, which controls *
  184.  *       the menu and encompasses all the MDI child windows. Does   *
  185.  *       the major part of the message processing. Specifically, in *
  186.  *       response to:                           *
  187.  *                                      *
  188.  *           WM_CREATE      : Creates and displays the "frame". *
  189.  *                                      *
  190.  *           WM_INITMENU    : Sets up the state of the menu.    *
  191.  *                                      *
  192.  *           WM_WININICHANGE &  : If default printer characteristics*
  193.  *           WM_DEVMODECHANGE     have been changed, reinitialises  *
  194.  *                    printer DC.               *
  195.  *                                      *
  196.  *           WM_COMMAND     : Passes control to a command-      *
  197.  *                    handling function.            *
  198.  *                                      *
  199.  *           WM_CLOSE       : Quits the app. if all the child   *
  200.  *                    windows agree.            *
  201.  *                                      *
  202.  *           WM_QUERYENDSESSION : Checks that all child windows     *
  203.  *                    agree to quit.            *
  204.  *                                      *
  205.  *           WM_DESTROY     : Destroys frame window and quits   *
  206.  *                    app.                  *
  207.  *                                      *
  208.  ****************************************************************************/
  209. LONG FAR PASCAL __export PPFrameWndProc ( hwnd, msg, wParam, lParam )
  210.  
  211. register HWND    hwnd;
  212. UINT         msg;
  213. register WPARAM    wParam;
  214. LPARAM         lParam;
  215.  
  216. {
  217.     switch (msg){
  218.     case WM_CREATE:{
  219.  
  220.         CLIENTCREATESTRUCT ccs;
  221.         HDC hdc;
  222.  
  223.         /* Find window menu where children will be listed */
  224.         ccs.hWindowMenu = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
  225.         ccs.idFirstChild = IDM_WINDOWCHILD;
  226.  
  227.         /* Create the MDI client filling the client area */
  228.         hwndMDIClient = CreateWindow ("mdiclient",
  229.                       NULL,
  230.                       WS_CHILD | WS_CLIPCHILDREN |
  231.                       WS_VSCROLL | WS_HSCROLL,
  232.                       0,
  233.                       0,
  234.                       0,
  235.                       0,
  236.                       hwnd,
  237.                       0xCAC,
  238.                       hInst,
  239.                       (LPSTR)&ccs);
  240.  
  241.         ShowWindow (hwndMDIClient,SW_SHOW);
  242.  
  243.         /* Check if printer can be initialized */
  244.         if (hdc = GetPrinterDC ()){
  245.         DeleteDC (hdc);
  246.         }
  247.  
  248.         break;
  249.     }
  250.  
  251.     case WM_INITMENU:
  252.         /* Set up the menu state */
  253.         InitializeMenu ((HMENU)wParam);
  254.         break;
  255.  
  256.     case WM_WININICHANGE:
  257.     case WM_DEVMODECHANGE:{
  258.  
  259.         /*  If control panel changes default printer characteristics,
  260.          *  reinitialize our printer information...
  261.          */
  262.         HDC hdc;
  263.  
  264.         if (hdc = GetPrinterDC ()){
  265.         DeleteDC (hdc);
  266.         }
  267.         break;
  268.     }
  269.  
  270.  
  271.     case WM_COMMAND:
  272.         /* Direct all menu selection or accelerator commands to another
  273.          * function
  274.          */
  275.         CommandHandler (hwnd,wParam);
  276.         break;
  277.  
  278.     case WM_CLOSE:
  279.         /* don't close if any children cancel the operation */
  280.         if (!QueryCloseAllChildren ())
  281.         break;
  282.         DestroyWindow (hwnd);
  283.         break;
  284.  
  285.     case WM_QUERYENDSESSION:
  286.         /*  Before session ends, check that all files are saved */
  287.         return QueryCloseAllChildren ();
  288.  
  289.     case WM_DESTROY:
  290.         PostQuitMessage (0);
  291.         break;
  292.  
  293.     default:
  294.         /*  use DefFrameProc() instead of DefWindowProc() since there
  295.          *  are things that have to be handled differently because of MDI
  296.          */
  297.         return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
  298.     }
  299.     return 0;
  300. }
  301.  
  302. /****************************************************************************
  303.  *                                      *
  304.  *  FUNCTION   : PPMDIChildWndProc ( hwnd, msg, wParam, lParam )            *
  305.  *                                      *
  306.  *  PURPOSE    : The window function for the individual document windows,   *
  307.  *       each of which has a "note". Each of these windows contain  *
  308.  *       one multi-line edit control filling their client area.     *
  309.  *       In response to the following:                  *
  310.  *                                      *
  311.  *           WM_CREATE      : Creates & diplays an edit control *
  312.  *                    and does some initialization.     *
  313.  *                                      *
  314.  *           WM_MDIACTIVATE : Activates/deactivates the child.  *
  315.  *                                      *
  316.  *           WM_SETFOCUS    : Sets focus on the edit control.   *
  317.  *                                      *
  318.  *           WM_SIZE        : Resizes the edit control.     *
  319.  *                                      *
  320.  *           WM_COMMAND     : Processes some of the edit        *
  321.  *                    commands, saves files and alters  *
  322.  *                    the edit wrap state.          *
  323.  *                                      *
  324.  *           WM_CLOSE       : Closes child if it is ok to do so.*
  325.  *                                      *
  326.  *           WM_QUERYENDSESSION : Same as above.            *
  327.  *                                      *
  328.  ****************************************************************************/
  329.  
  330. LONG FAR PASCAL __export PPMDIChildWndProc ( hwnd, msg, wParam, lParam )
  331.  
  332. register HWND   hwnd;
  333. UINT        msg;
  334. register WPARAM   wParam;
  335. LPARAM        lParam;
  336.  
  337. {
  338.     HWND hwndEdit;
  339.  
  340.     switch (msg){
  341.     case WM_CREATE:
  342.         /* Create an edit control */
  343.         hwndEdit = CreateWindow ("edit",
  344.                      NULL,
  345.                      WS_CHILD|WS_HSCROLL|WS_MAXIMIZE|WS_VISIBLE|WS_VSCROLL|ES_AUTOHSCROLL|ES_AUTOVSCROLL|ES_MULTILINE,
  346.                      0,
  347.                      0,
  348.                      0,
  349.                      0,
  350.                      hwnd,
  351.                      ID_EDIT,
  352.                      hInst,
  353.                      NULL);
  354.  
  355.         /* Subclass this window for handwriting support.  Easier to
  356.             just use hedit's, but this allows ProcessWriting to
  357.             be demostrating.
  358.         */
  359.         
  360.         lpfnEditProc = (FARPROC)GetWindowLong(hwndEdit, GWL_WNDPROC);
  361.             lpfnFakeProc = MakeProcInstance((FARPROC)FakeProc, hInst);
  362.             SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG)lpfnFakeProc);
  363.  
  364.         /* Remember the window handle and initialize some window attributes */
  365.         SetWindowWord (hwnd, GWW_HWNDEDIT, (WORD)hwndEdit);
  366.         SetWindowWord (hwnd, GWW_CHANGED, FALSE);
  367.         SetWindowWord (hwnd, GWW_WORDWRAP, FALSE);
  368.         SetWindowWord (hwnd, GWW_UNTITLED, TRUE);
  369.         SetFocus (hwndEdit);
  370.         break;
  371.  
  372.     case WM_MDIACTIVATE:
  373.         /* If we're activating this child, remember it */
  374.         if (wParam){
  375.         hwndActive     = hwnd;
  376.         hwndActiveEdit = (HWND)GetWindowWord (hwnd, GWW_HWNDEDIT);
  377.         }
  378.         else{
  379.         hwndActive     = NULL;
  380.         hwndActiveEdit = NULL;
  381.         }
  382.         break;
  383.  
  384.     case WM_QUERYENDSESSION:
  385.         /* Prompt to save the child */
  386.         return !QueryCloseChild (hwnd);
  387.  
  388.     case WM_CLOSE:
  389.         /* If its OK to close the child, do so, else ignore */
  390.         if (QueryCloseChild (hwnd))
  391.         goto CallDCP;
  392.         else
  393.         break;
  394.  
  395.     case WM_SIZE:{
  396.         RECT rc;
  397.  
  398.         /* On creation or resize, size the edit control. */
  399.         hwndEdit = GetWindowWord (hwnd, GWW_HWNDEDIT);
  400.         GetClientRect (hwnd, &rc);
  401.         MoveWindow (hwndEdit,
  402.             rc.left,
  403.             rc.top,
  404.             rc.right-rc.left,
  405.             rc.bottom-rc.top,
  406.             TRUE);
  407.         goto CallDCP;
  408.     }
  409.  
  410.     case WM_SETFOCUS:
  411.         SetFocus (GetWindowWord (hwnd, GWW_HWNDEDIT));
  412.         break;
  413.  
  414.     case WM_COMMAND:
  415.         switch (wParam){
  416.         case ID_EDIT:
  417.             switch (HIWORD(lParam)){
  418.             case EN_CHANGE:
  419.  
  420.                 /* If the contents of the edit control have changed,
  421.                    set the changed flag
  422.                  */
  423.                 SetWindowWord (hwnd, GWW_CHANGED, TRUE);
  424.                 break;
  425.  
  426.             case EN_ERRSPACE:
  427.                 /* If the control is out of space, honk */
  428.                 MessageBeep (0);
  429.                 break;
  430.  
  431.             default:
  432.                 goto CallDCP;
  433.             }
  434.             break;
  435.  
  436.         case IDM_FILESAVE:
  437.             /* If empty file, ignore save */
  438.             if ((GetWindowWord(hwnd, GWW_UNTITLED)) && (!ChangeFile(hwnd)))
  439.             break;
  440.  
  441.             /* Save the contents of the edit control and reset the
  442.              * changed flag
  443.              */
  444.             SaveFile (hwnd);
  445.             SetWindowWord (hwnd, GWW_CHANGED, FALSE);
  446.             break;
  447.  
  448.         case IDM_EDITWRAP: {
  449.             int fWrap = GetWindowWord (hwnd, GWW_WORDWRAP);
  450.  
  451.             /* Set the wrap state, or report it */
  452.             if (LOWORD (lParam)){
  453.             fWrap = !fWrap;
  454.             SetWrap (hwnd, fWrap);
  455.             }
  456.  
  457.             /* return wrap state */
  458.             return fWrap;
  459.         }
  460.  
  461.         default:
  462.             goto CallDCP;
  463.         }
  464.         break;
  465.  
  466.     default:
  467. CallDCP:
  468.         /* Again, since the MDI default behaviour is a little different,
  469.          * call DefMDIChildProc instead of DefWindowProc()
  470.          */
  471.         return DefMDIChildProc (hwnd, msg, wParam, lParam);
  472.     }
  473.     return FALSE;
  474. }
  475.  
  476.  
  477. /****************************************************************************
  478.  *                                      *
  479.  *  FUNCTION   : AboutDlgProc ( hwnd, msg, wParam, lParam )         *
  480.  *                                      *
  481.  *  PURPOSE    : Dialog function for the About PenPad... dialog.        *
  482.  *                                      *
  483.  ****************************************************************************/
  484. BOOL FAR PASCAL __export AboutDlgProc ( hwnd, msg, wParam, lParam )
  485. HWND          hwnd;
  486. register WORD msg;
  487. register WORD wParam;
  488. LONG          lParam;
  489. {
  490.     lParam;                 /* Needed to prevent compiler warning message */
  491.  
  492.     switch (msg){
  493.     case WM_INITDIALOG:
  494.         /* nothing to initialize */
  495.         break;
  496.  
  497.     case WM_COMMAND:
  498.         switch (wParam){
  499.         case IDOK:
  500.         case IDCANCEL:
  501.             EndDialog(hwnd, 0);
  502.             break;
  503.  
  504.         default:
  505.             return FALSE;
  506.         }
  507.         break;
  508.  
  509.     default:
  510.         return FALSE;
  511.     }
  512.  
  513.     return TRUE;
  514. }
  515.  
  516. /****************************************************************************
  517.  *                                      *
  518.  *  FUNCTION   : Initializemenu ( hMenu )                   *
  519.  *                                      *
  520.  *  PURPOSE    : Sets up greying, enabling and checking of main menu items  *
  521.  *       based on the app's state.                                  *
  522.  *                                      *
  523.  ****************************************************************************/
  524. VOID NEAR PASCAL InitializeMenu ( hmenu )
  525. register HANDLE hmenu;
  526. {
  527.     register WORD status;
  528.     int       i;
  529.     long      l;
  530.  
  531.     /* Is there any active child to talk to? */
  532.     if (hwndActiveEdit){
  533.     /* If edit control can respond to an undo request, enable the
  534.      * undo selection.
  535.      */
  536.     if (SendMessage (hwndActiveEdit, EM_CANUNDO, 0, 0L))
  537.         status = MF_ENABLED;
  538.     else
  539.         status = MF_GRAYED;
  540.     EnableMenuItem (hmenu, IDM_EDITUNDO, status);
  541.  
  542.     /* If edit control is non-empty, allow cut/copy/clear */
  543.     l      = SendMessage (hwndActiveEdit, EM_GETSEL, 0, 0L);
  544.     status = (HIWORD(l) == LOWORD(l)) ? MF_GRAYED : MF_ENABLED;
  545.     EnableMenuItem (hmenu, IDM_EDITCUT, status);
  546.     EnableMenuItem (hmenu, IDM_EDITCOPY, status);
  547.     EnableMenuItem (hmenu, IDM_EDITCLEAR, status);
  548.  
  549.     status=MF_GRAYED;
  550.     /* If the clipboard contains some CF_TEXT data, allow paste */
  551.     if (OpenClipboard (hwndFrame)){
  552.         int wFmt = 0;
  553.  
  554.         while (wFmt = EnumClipboardFormats (wFmt))
  555.         if (wFmt == CF_TEXT){
  556.             status = MF_ENABLED;
  557.             break;
  558.         }
  559.  
  560.         CloseClipboard ();
  561.     }
  562.     EnableMenuItem (hmenu, IDM_EDITPASTE, status);
  563.  
  564.     /* Set the word wrap state for the window */
  565.     if ((WORD) SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 0L))
  566.         status = MF_CHECKED;
  567.     else
  568.         status = MF_UNCHECKED;
  569.     CheckMenuItem (hmenu, IDM_EDITWRAP, status);
  570.  
  571.     /* Enable search menu items only if there is a search string */
  572.     if (*szSearch)
  573.         status = MF_ENABLED;
  574.     else
  575.         status = MF_GRAYED;
  576.     EnableMenuItem (hmenu, IDM_SEARCHNEXT, status);
  577.     EnableMenuItem (hmenu, IDM_SEARCHPREV, status);
  578.  
  579.     /* Enable File/Print only if a printer is available */
  580.     status = iPrinter ? MF_ENABLED : MF_GRAYED;
  581.     EnableMenuItem (hmenu, IDM_FILEPRINT, status);
  582.  
  583.     /* select all and wrap toggle always enabled */
  584.     status = MF_ENABLED;
  585.     EnableMenuItem(hmenu, IDM_EDITSELECT, status);
  586.     EnableMenuItem(hmenu, IDM_EDITWRAP, status);
  587.     EnableMenuItem(hmenu, IDM_SEARCHFIND, status);
  588.     }
  589.     else {
  590.     /* There are no active child windows */
  591.     status = MF_GRAYED;
  592.  
  593.     /* No active window, so disable everything */
  594.     for (i = IDM_EDITFIRST; i <= IDM_EDITLAST; i++)
  595.         EnableMenuItem (hmenu, i, status);
  596.  
  597.     CheckMenuItem (hmenu, IDM_EDITWRAP, MF_UNCHECKED);
  598.  
  599.     for (i = IDM_SEARCHFIRST; i <= IDM_SEARCHLAST; i++)
  600.         EnableMenuItem (hmenu, i, status);
  601.  
  602.     EnableMenuItem (hmenu, IDM_FILEPRINT, status);
  603.  
  604.     }
  605.  
  606.     /* The following menu items are enabled if there is an active window */
  607.     EnableMenuItem (hmenu, IDM_FILESAVE, status);
  608.     EnableMenuItem (hmenu, IDM_FILESAVEAS, status);
  609.     EnableMenuItem (hmenu, IDM_WINDOWTILE, status);
  610.     EnableMenuItem (hmenu, IDM_WINDOWCASCADE, status);
  611.     EnableMenuItem (hmenu, IDM_WINDOWICONS, status);
  612.     EnableMenuItem (hmenu, IDM_WINDOWCLOSEALL, status);
  613.  
  614.     /* Allow printer setup only if printer driver supports device initialization */
  615.     if (iPrinter < 2)
  616.     status = MF_GRAYED;
  617.     EnableMenuItem ( hmenu, IDM_FILESETUP, status);
  618.  
  619. }
  620.  
  621. /****************************************************************************
  622.  *                                      *
  623.  *  FUNCTION   : CloseAllChildren ()                        *
  624.  *                                      *
  625.  *  PURPOSE    : Destroys all MDI child windows.                *
  626.  *                                      *
  627.  ****************************************************************************/
  628. VOID NEAR PASCAL CloseAllChildren ()
  629. {
  630.     register HWND hwndT;
  631.  
  632.      /* kludge : if not minimized, closeall rips. multipad (win SDK sample)
  633.          also has this bug. Bug was reported, but not fixed yet. */
  634.     ShowWindow(hwndMDIClient,SW_MINIMIZE);
  635.  
  636.     /* hide the MDI client window to avoid multiple repaints */
  637.     ShowWindow(hwndMDIClient,SW_HIDE);
  638.  
  639.     /* As long as the MDI client has a child, destroy it */
  640.     while ( hwndT = GetWindow (hwndMDIClient, GW_CHILD)){
  641.  
  642.     /* Skip the icon title windows */
  643.     while (hwndT && GetWindow (hwndT, GW_OWNER))
  644.         hwndT = GetWindow (hwndT, GW_HWNDNEXT);
  645.  
  646.     if (!hwndT)
  647.         break;
  648.  
  649.     SendMessage (hwndMDIClient, WM_MDIDESTROY, (WORD)hwndT, 0L);
  650.     }
  651. }
  652.  
  653. /****************************************************************************
  654.  *                                      *
  655.  *  FUNCTION   : CommandHandler ()                      *
  656.  *                                      *
  657.  *  PURPOSE    : Processes all "frame" WM_COMMAND messages.         *
  658.  *                                      *
  659.  ****************************************************************************/
  660. VOID NEAR PASCAL CommandHandler ( hwnd, wParam )
  661. register HWND hwnd;
  662. register WORD wParam;
  663.  
  664. {
  665.     switch (wParam){
  666.     case IDM_FILENEW:
  667.         /* Add a new, empty MDI child */
  668.         AddFile (NULL);
  669.         break;
  670.  
  671.     case IDM_FILEOPEN:
  672.         ReadFile (hwnd);
  673.         break;
  674.  
  675.     case IDM_FILESAVE:
  676.         /* Save the active child MDI */
  677.         SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
  678.         break;
  679.  
  680.     case IDM_FILESAVEAS:
  681.         /* Save active child MDI under another name */
  682.         if (ChangeFile (hwndActive))
  683.         SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
  684.         break;
  685.  
  686.     case IDM_FILEPRINT:
  687.         /* Print the active child MDI */
  688.         PrintFile (hwndActive);
  689.         break;
  690.  
  691.     case IDM_FILESETUP:
  692.         /* Set up the printer environment for this app */
  693.         GetInitializationData (hwnd);
  694.         break;
  695.  
  696.     case IDM_FILEMENU:{
  697.  
  698.           /* lengthen / shorten the size of the MDI menu */
  699.           HMENU hMenu;
  700.           HMENU hWindowMenu;
  701.           int i;
  702.  
  703.           if (lpMenu == IDPENPAD){
  704.           lpMenu = IDPENPAD2;
  705.           i  = SHORTMENU;
  706.           }
  707.           else{
  708.           lpMenu = IDPENPAD;
  709.           i  = WINDOWMENU;
  710.           }
  711.  
  712.           hMenu = LoadMenu (hInst, lpMenu);
  713.           hWindowMenu = GetSubMenu (hMenu, i);
  714.  
  715.           /* Set the new menu */
  716.           hMenu = (HMENU)SendMessage (hwndMDIClient,
  717.                       WM_MDISETMENU,
  718.                       0,
  719.                       MAKELONG(hMenu,hWindowMenu));
  720.  
  721.           DestroyMenu (hMenu);
  722.           DrawMenuBar (hwndFrame);
  723.           break;
  724.     }
  725.  
  726.     case IDM_FILEEXIT:
  727.         /* Close Penpad */
  728.         SendMessage (hwnd, WM_CLOSE, 0, 0L);
  729.         break;
  730.  
  731.     case IDM_HELPABOUT:{
  732.         /* Bring up the ubiquitous Ego box */
  733.         FARPROC lpfn;
  734.  
  735.         lpfn = MakeProcInstance(AboutDlgProc, hInst);
  736.         DialogBox (hInst, IDD_ABOUT, hwnd, lpfn);
  737.         FreeProcInstance (lpfn);
  738.         break;
  739.     }
  740.  
  741.     /* The following are edit commands. Pass these off to the active
  742.      * child's edit control window.
  743.      */
  744.     case IDM_EDITCOPY:
  745.         SendMessage (hwndActiveEdit, WM_COPY, 0, 0L);
  746.         break;
  747.  
  748.     case IDM_EDITPASTE:
  749.         SendMessage (hwndActiveEdit, WM_PASTE, 0, 0L);
  750.         break;
  751.  
  752.     case IDM_EDITCUT:
  753.         SendMessage (hwndActiveEdit, WM_CUT, 0, 0L);
  754.         break;
  755.  
  756.     case IDM_EDITCLEAR:
  757.         SendMessage (hwndActiveEdit, EM_REPLACESEL, 0,( LONG)(LPSTR)"");
  758.         break;
  759.  
  760.     case IDM_EDITSELECT:
  761.         SendMessage (hwndActiveEdit, EM_SETSEL, 0, MAKELONG(0, 0xe000));
  762.         break;
  763.  
  764.     case IDM_EDITUNDO:
  765.         SendMessage (hwndActiveEdit, EM_UNDO, 0, 0L);
  766.         break;
  767.  
  768.     case IDM_EDITWRAP:
  769.         SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 1L);
  770.         break;
  771.  
  772.     case IDM_SEARCHFIND:
  773.         /* Put up the find dialog box */
  774.         Find ();
  775.         break;
  776.  
  777.     case IDM_SEARCHNEXT:
  778.         /* Find next occurence */
  779.         FindNext ();
  780.         break;
  781.  
  782.     case IDM_SEARCHPREV:
  783.         /* Find previous occurence */
  784.         FindPrev ();
  785.         break;
  786.  
  787.     /* The following are window commands - these are handled by the
  788.      * MDI Client.
  789.      */
  790.     case IDM_WINDOWTILE:
  791.         /* Tile MDI windows */
  792.         SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
  793.         break;
  794.  
  795.     case IDM_WINDOWCASCADE:
  796.         /* Cascade MDI windows */
  797.         SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
  798.         break;
  799.  
  800.     case IDM_WINDOWICONS:
  801.         /* Auto - arrange MDI icons */
  802.         SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
  803.         break;
  804.  
  805.     case IDM_WINDOWCLOSEALL:
  806.         /* Abort operation if something is not saved */
  807.         if (!QueryCloseAllChildren())
  808.         break;
  809.  
  810.         CloseAllChildren();
  811.  
  812.         
  813.          /* kludge : since we minimized the window to prevent closeall tp rip.
  814.              we must now restore it */
  815.          ShowWindow( hwndMDIClient, SW_RESTORE);
  816.         
  817.          /* Show the window since CloseAllChilren() hides the window
  818.          * for fewer repaints.
  819.          */
  820.         
  821.          ShowWindow( hwndMDIClient, SW_SHOW);
  822.  
  823.         break;
  824.  
  825.     default:
  826.        /*
  827.         * This is essential, since there are frame WM_COMMANDS generated
  828.         * by the MDI system for activating child windows via the
  829.         * window menu.
  830.         */
  831.         DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND, wParam, 0L);
  832.     }
  833. }
  834. /****************************************************************************
  835.  *                                      *
  836.  *  FUNCTION   : SetWrap ()                         *
  837.  *                                      *
  838.  *  PURPOSE    : Changes the word wrapping in an edit control. Since this   *
  839.  *       cannot be done by direct means, the function creates a new *
  840.  *       edit control, moves data from the old control to the new   *
  841.  *       control and destroys the original control. Note that the   *
  842.  *       function assumes that the child being modified is currently*
  843.  *       active.                            *       *
  844.  *                                      *
  845.  ****************************************************************************/
  846.  
  847. VOID NEAR PASCAL SetWrap(hwnd, fWrap)
  848. HWND hwnd;
  849. BOOL fWrap;
  850.  
  851. {
  852.     LONG    dws;
  853.     HANDLE  hT;
  854.     HANDLE  hTT;
  855.     HWND    hwndOld;
  856.     HWND    hwndNew;
  857.     FARPROC lpfnT;
  858.  
  859.     /* Change word wrap mode */
  860.     SetWindowWord (hwnd, GWW_WORDWRAP, fWrap);
  861.  
  862.     /* Create the appropriate window style, adding a horizontal scroll
  863.      * facility if wrapping is not present.
  864.      */
  865.     dws = WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE;
  866.     if (!fWrap)
  867.     dws |= WS_HSCROLL | ES_AUTOHSCROLL;
  868.  
  869.     /* Create a new child window */
  870.     hwndNew = CreateWindow ( "edit",
  871.                  NULL,
  872.                  dws,
  873.                  0,
  874.                  SW_SHOW,
  875.                  0,
  876.                  0,
  877.                  hwnd,
  878.                  ID_EDIT,
  879.                  hInst,
  880.                  NULL);
  881.  
  882.     /* Get handle to current edit control */
  883.     hwndOld = GetWindowWord (hwnd, GWW_HWNDEDIT);
  884.  
  885.     /* Get the data handle of the old control */
  886.     hT = (HANDLE)SendMessage (hwndOld, EM_GETHANDLE, 0, 0L);
  887.  
  888.     /* Get the subclassed window proc */
  889.     lpfnT = (FARPROC)GetWindowLong(hwndOld, GWL_WNDPROC);
  890.     SetWindowLong(hwndNew, GWL_WNDPROC, (LONG)lpfnT);
  891.  
  892.     /* Create a dummy data handle and make it the handle to
  893.      * the old edit control( hT still references the text of
  894.      * old control).
  895.      */
  896.     hTT = LocalAlloc (LHND, 0);
  897.     SendMessage (hwndOld, EM_SETHANDLE, hTT, 0L);
  898.  
  899.     /* Make the new window the window of interest and destroy the
  900.      * old control.
  901.      */
  902.     SetWindowWord (hwnd, GWW_HWNDEDIT, hwndNew);
  903.     hwndActiveEdit = hwndNew;
  904.     DestroyWindow (hwndOld);
  905.  
  906.     /* Cause the window to be properly sized */
  907.     SendMessage (hwnd, WM_SIZE, 0, 0L);
  908.  
  909.     /* Free the new window's old data handle and set it to
  910.      * hT (text of old edit control)
  911.      */
  912.     LocalFree ((HANDLE)SendMessage (hwndNew, EM_GETHANDLE, 0, 0L));
  913.     SendMessage (hwndNew, EM_SETHANDLE, hT, 0L);
  914.  
  915.     ShowWindow (hwndNew, SW_SHOW);
  916.  
  917.     /* Set focus to the new edit control */
  918.     SetFocus (hwndNew);
  919.  
  920. }
  921.  
  922.  
  923. /****************************************************************************
  924.  *                                      *
  925.  *  FUNCTION   : PPError ( hwnd, flags, id, ...)                *
  926.  *                                      *
  927.  *  PURPOSE    : Flashes a Message Box to the user. The format string is    *
  928.  *       taken from the STRINGTABLE.                    *
  929.  *                                      *
  930.  *  RETURNS    : Returns value returned by MessageBox() to the caller.      *
  931.  *                                      *
  932.  ****************************************************************************/
  933. short FAR CDECL PPError(hwnd, bFlags, id, ...)
  934. HWND hwnd;
  935. WORD bFlags;
  936. WORD id;
  937. {
  938.     char sz[160];
  939.     char szFmt[128];
  940.  
  941.      hwnd;                  /* Needed to prevent compiler warning message */
  942.  
  943.     LoadString (hInst, id, szFmt, sizeof (szFmt));
  944.     wvsprintf (sz, szFmt, (LPSTR)(&id + 1));
  945.     LoadString (hInst, IDS_APPNAME, szFmt, sizeof (szFmt));
  946.     return MessageBox (hwndFrame, sz, szFmt, bFlags);
  947. }
  948.  
  949.  
  950. /****************************************************************************
  951.  *                                      *
  952.  *  FUNCTION   : QueryCloseAllChildren()                    *
  953.  *                                      *
  954.  *  PURPOSE    : Asks the child windows if it is ok to close up app. Nothing*
  955.  *       is destroyed at this point. The z-order is not changed.    *
  956.  *                                      *
  957.  *  RETURNS    : TRUE - If all children agree to the query.         *
  958.  *       FALSE- If any one of them disagrees.               *
  959.  *                                      *
  960.  ****************************************************************************/
  961.  
  962. BOOL NEAR PASCAL QueryCloseAllChildren()
  963. {
  964.     register HWND hwndT;
  965.  
  966.     for ( hwndT = GetWindow (hwndMDIClient, GW_CHILD);
  967.       hwndT;
  968.       hwndT = GetWindow (hwndT, GW_HWNDNEXT)       ){
  969.  
  970.     /* Skip if an icon title window */
  971.     if (GetWindow (hwndT, GW_OWNER))
  972.         continue;
  973.  
  974.     if (SendMessage (hwndT, WM_QUERYENDSESSION, 0, 0L))
  975.         return FALSE;
  976.     }
  977.     return TRUE;
  978. }
  979.  
  980. /****************************************************************************
  981.  *                                      *
  982.  *  FUNCTION   : QueryCloseChild (hwnd)                     *
  983.  *                                      *
  984.  *  PURPOSE    : If the child MDI is unsaved, allow the user to save, not   *
  985.  *               save, or cancel the close operation.                       *
  986.  *                                      *
  987.  *  RETURNS    : TRUE  - if user chooses save or not save, or if the file   *
  988.  *                       has not changed.                                   *
  989.  *       FALSE - otherwise.                     *
  990.  *                                      *
  991.  ****************************************************************************/
  992.  
  993. BOOL NEAR PASCAL QueryCloseChild(hwnd)
  994. register HWND hwnd;
  995. {
  996.     char     sz [64];
  997.     register int i;
  998.  
  999.     /* Return OK if edit control has not changed. */
  1000.     if (!GetWindowWord (hwnd, GWW_CHANGED))
  1001.     return TRUE;
  1002.  
  1003.     GetWindowText (hwnd, sz, sizeof(sz));
  1004.  
  1005.     /* Ask user whether to save / not save / cancel */
  1006.     i = PPError (hwnd,
  1007.          MB_YESNOCANCEL|MB_ICONQUESTION,IDS_CLOSESAVE,
  1008.          (LPSTR)sz);
  1009.  
  1010.     switch (i){
  1011.     case IDYES:
  1012.         /* User wants file saved */
  1013.         SaveFile(hwnd);
  1014.         break;
  1015.  
  1016.     case IDNO:
  1017.         /* User doesn't want file saved */
  1018.         break;
  1019.  
  1020.     default:
  1021.         /* We couldn't do the messagebox, or not ok to close */
  1022.         return FALSE;
  1023.     }
  1024.     return TRUE;
  1025. }
  1026.  
  1027.  
  1028. /****************************************************************************
  1029.  *                                      *
  1030.  *  FUNCTION   : FakeProc ( hwnd, msg, wParam, lParam )             *
  1031.  *                                      *
  1032.  *  PURPOSE    : The subclassed window function for the individual document *
  1033.  *       windows.  It is this simple modification that allows the   *
  1034.  *       support for pens.  Note the difference between this        *
  1035.  *       file and the original non-pen-aware PENPAD.OLD.        *
  1036.  *                                      *
  1037.  *       In response to the following:                  *
  1038.  *                                      *
  1039.  *           WM_SETCURSOR   : Sets the cursor to a pen while    *
  1040.  *                    cursor is in this window.         *
  1041.  *                                      *
  1042.  *           WM_RBUTTONDOWN and                     *
  1043.  *           WM_RBUTTONUP   : Translates to WM_LBUTTON* message.*
  1044.  *                                      *
  1045.  *           WM_LBUTTONDOWN : Invokes the recognizer via the    *
  1046.  *                    ProcessWriting API.           *
  1047.  *                                      *
  1048.  *           WM_RCRESULT    : Returns FALSE.  This message is   *
  1049.  *                    a Pen Windows message sent by the *
  1050.  *                    recognizer when results are       *
  1051.  *                    available.                *
  1052.  *                                      *
  1053.  ****************************************************************************/
  1054.  
  1055. LONG FAR PASCAL __export FakeProc ( hwnd, msg, wParam, lParam )
  1056.  
  1057. HWND    hwnd;
  1058. WORD    msg;
  1059. WORD    wParam;
  1060. LONG    lParam;
  1061.  
  1062. {
  1063.     switch (msg){
  1064.  
  1065.     case WM_SETCURSOR:
  1066.         /* Change cursor to a pen if in the client area of edit control */
  1067.         if (LOWORD(lParam) == HTCLIENT)
  1068.             {
  1069.             SetCursor(hCursor);
  1070.             return TRUE;
  1071.             }
  1072.         break;
  1073.  
  1074.     case WM_LBUTTONDOWN:
  1075.         /* Check to see if button-down should invoke recognizer */
  1076.         if ((*lpfnProcessWriting)(hwnd, NULL) >= 0)
  1077.             return TRUE;    /* Recognition has started, do not pass to default proc */
  1078.         break;              /* Else, do default edit processing */
  1079.  
  1080.  
  1081.     case WM_RCRESULT:
  1082.        /* Returning FALSE will cause default recognition handling
  1083.           to occur.
  1084.  
  1085.             ProcessWriting will convert the result to messages that this
  1086.             WndProc already handles (such as WM_CHAR's, WM_LBUTTONDOWNS)
  1087.             We need only check for gestures that need to detect
  1088.             if there is a selection and if not, select word or character
  1089.             under gesture
  1090.        */
  1091.         {
  1092.         LPRCRESULT lpr = (LPRCRESULT)lParam;
  1093.  
  1094.        /*   Check if a gesture, but not a circle-letter gesture which has been
  1095.             mapped to one of the standard gestures. */ 
  1096.  
  1097.         if ((lpr->wResultsType&RCRT_GESTURE) && (lpr->wResultsType&RCRT_GESTURETRANSLATED)==0)
  1098.             {
  1099.             switch (*lpr->lpsyv)
  1100.                 {
  1101.             case SYV_COPY:
  1102.             case SYV_CUT:
  1103.             case SYV_CLEAR:
  1104.                 {
  1105.                 LONG lSel = SendMessage(hwnd, EM_GETSEL, 0, 0L);
  1106.                 POINT ptHotSpot;
  1107.  
  1108.                 if (LOWORD(lSel) >= HIWORD(lSel))
  1109.                    /* There is no selection, so send in doubleclick to
  1110.                         select word underselection (or for clear, just set
  1111.                         insertion point since we want to delete a character. */ 
  1112.                     {
  1113.                     LONG lParamPt;
  1114.                     ptHotSpot = lpr->syg.rgpntHotSpots[0];
  1115.  
  1116.                     (*lpfnTPtoDP)(&ptHotSpot, 1);
  1117.                     ScreenToClient(hwnd, &ptHotSpot);
  1118.                     lParamPt = *(LONG FAR *)&ptHotSpot;
  1119.                     SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, lParamPt);
  1120.                     SendMessage(hwnd, WM_LBUTTONUP, 0, lParamPt);
  1121.                     if (*lpr->lpsyv != SYV_CLEAR)
  1122.                         {
  1123.                         SendMessage(hwnd, WM_LBUTTONDBLCLK, MK_LBUTTON, lParamPt);
  1124.                         SendMessage(hwnd, WM_LBUTTONUP, 0, lParamPt);
  1125.                         }
  1126.                     else
  1127.                         {
  1128.                        /*   If we send this window a CLEAR and nothing is selected,
  1129.                             the character to the right will not be deleted, so
  1130.                             send a delete key. */ 
  1131.                         SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 0L);
  1132.                         SendMessage(hwnd, WM_KEYUP, VK_DELETE, 0L);
  1133.                         return 0;
  1134.                         }
  1135.  
  1136.                    /* Fall through and return false, will receive one of
  1137.                         WM_COPY, WM_CUT */ 
  1138.                     }
  1139.  
  1140.                 }
  1141.                 break;
  1142.  
  1143.             default:
  1144.                 break;
  1145.                 }
  1146.             }
  1147.         return FALSE;
  1148.         }
  1149.  
  1150.     default:
  1151.         /* Since this window procedure is a subclass, must call the
  1152.            real window procedure now. */
  1153.         break;
  1154.     }
  1155.     return CallWindowProc (lpfnEditProc, hwnd, msg, wParam, lParam);
  1156. }
  1157.