home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / d / d020_1_4 / 6.ddi / PRNTFILE / PRNTFILE.C next >
Encoding:
C/C++ Source or Header  |  1990-06-01  |  39.1 KB  |  1,213 lines

  1. /****************************************************************************
  2.  
  3.     PROGRAM: PrntFile.c
  4.  
  5.     PURPOSE: Loads, saves, and edits text files
  6.  
  7.     FUNCTIONS:
  8.  
  9.         WinMain() - calls initialization function, processes message loop
  10.         InitApplication() - initializes window data and registers window
  11.         InitInstance() - saves instance handle and creates main window
  12.         MainWndProc() - processes messages
  13.         About() - processes messages for "About" dialog box
  14.         SaveAsDlg() - save file under different name
  15.         OpenDlg() - let user select a file, and open it.
  16.         UpdateListBox() - Update the list box of OpenDlg
  17.         ChangeDefExt() - Change the default extension
  18.         SeparateFile() - Separate filename and pathname
  19.         AddExt() - Add default extension
  20.         CheckFileName() - Check for wildcards, add extension if needed
  21.         SaveFile() - Save current file
  22.         QuerySaveFile() - Called when some action might lose current contents
  23.         SetNewBuffer() - Set new buffer for edit window
  24.  
  25. ****************************************************************************/
  26.  
  27. #include "windows.h"
  28. #include "prntfile.h"
  29.  
  30. HANDLE hInst;
  31.  
  32. HANDLE hAccTable;                                /* handle to accelerator table */
  33. HWND hEditWnd;                                      /* handle to edit window */
  34. HWND hwnd;                                       /* handle to main window */
  35.  
  36. /* Additional includes needed for the fstat() function */
  37.  
  38. #include <sys\types.h>
  39. #include <sys\stat.h>
  40.  
  41. char FileName[128];
  42. char PathName[128];
  43. char OpenName[128];
  44. char DefPath[128];
  45. char DefSpec[13] = "*.*";
  46. char DefExt[] = ".txt";
  47. char str[255];
  48.  
  49. HANDLE hEditBuffer;                       /* handle to editing buffer      */
  50. HANDLE hOldBuffer;                        /* old buffer handle        */
  51. HANDLE hHourGlass;                        /* handle to hourglass cursor      */
  52. HANDLE hSaveCursor;                       /* current cursor handle      */
  53. int hFile;                                /* file handle              */
  54. int count;                                /* number of chars read or written */
  55. PSTR pBuffer;                             /* address of read/write buffer    */
  56. OFSTRUCT OfStruct;                        /* information from OpenFile()     */
  57. struct stat FileStatus;                   /* information from fstat()      */
  58. BOOL bChanges = FALSE;                    /* TRUE if the file is changed     */
  59. BOOL bSaveEnabled = FALSE;                /* TRUE if text in the edit buffer */
  60. PSTR pEditBuffer;                         /* address of the edit buffer      */
  61. RECT Rect;                                /* dimension of the client window  */
  62.  
  63. char Untitled[] =                         /* default window title      */
  64.      "Edit File - (untitled)";
  65.  
  66. /* Printer variables  */
  67.  
  68. HDC hPr;                            /* handle for printer device context     */
  69. int LineSpace;                      /* spacing between lines          */
  70. int LinesPerPage;                   /* lines per page                 */
  71. int CurrentLine;                    /* current line                   */
  72. int LineLength;                     /* line length                    */
  73. DWORD dwLines;                      /* number of lines to print       */
  74. DWORD dwIndex;                      /* index into lines to print      */
  75. char pLine[128];                    /* buffer to store lines before printing */
  76. TEXTMETRIC TextMetric;              /* information about character size      */
  77. BOOL bAbort;                        /* FALSE if user cancels printing      */
  78. HWND hAbortDlgWnd;
  79. FARPROC lpAbortDlg, lpAbortProc;
  80.  
  81. /****************************************************************************
  82.  
  83.     FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  84.  
  85.     PURPOSE: calls initialization function, processes message loop
  86.  
  87. ****************************************************************************/
  88.  
  89. int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
  90. HANDLE hInstance;
  91. HANDLE hPrevInstance;
  92. LPSTR lpCmdLine;
  93. int nCmdShow;
  94. {
  95.     MSG msg;
  96.  
  97.     if (!hPrevInstance)
  98.         if (!InitApplication(hInstance))
  99.             return (FALSE);
  100.  
  101.     if (!InitInstance(hInstance, nCmdShow))
  102.         return (FALSE);
  103.  
  104.     while (GetMessage(&msg, NULL, NULL, NULL)) {
  105.  
  106.     /* Only translate message if it is not an accelerator message */
  107.  
  108.         if (!TranslateAccelerator(hwnd, hAccTable, &msg)) {
  109.             TranslateMessage(&msg);
  110.             DispatchMessage(&msg); 
  111.         }
  112.     }
  113.     return (msg.wParam);
  114. }
  115.  
  116.  
  117. /****************************************************************************
  118.  
  119.     FUNCTION: InitApplication(HANDLE)
  120.  
  121.     PURPOSE: Initializes window data and registers window class
  122.  
  123. ****************************************************************************/
  124.  
  125. BOOL InitApplication(hInstance)
  126. HANDLE hInstance;
  127. {
  128.     WNDCLASS  wc;
  129.  
  130.     wc.style = NULL;
  131.     wc.lpfnWndProc = MainWndProc;
  132.     wc.cbClsExtra = 0;
  133.     wc.cbWndExtra = 0;
  134.     wc.hInstance = hInstance;
  135.     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  136.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  137.     wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
  138.     wc.lpszMenuName =  "PrntFileMenu";
  139.     wc.lpszClassName = "PrntFileWClass";
  140.  
  141.     return (RegisterClass(&wc));
  142. }
  143.  
  144.  
  145. /****************************************************************************
  146.  
  147.     FUNCTION:  InitInstance(HANDLE, int)
  148.  
  149.     PURPOSE:  Saves instance handle and creates main window
  150.  
  151. ****************************************************************************/
  152.  
  153. BOOL InitInstance(hInstance, nCmdShow)
  154.     HANDLE          hInstance;
  155.     int             nCmdShow;
  156. {
  157.     RECT            Rect;
  158.  
  159.     hInst = hInstance;
  160.  
  161.     hAccTable = LoadAccelerators(hInst, "PrntFileAcc");
  162.  
  163.     hwnd = CreateWindow(
  164.         "PrntFileWClass",
  165.         "PrntFile Sample Application",
  166.         WS_OVERLAPPEDWINDOW,
  167.         CW_USEDEFAULT,
  168.         CW_USEDEFAULT,
  169.         CW_USEDEFAULT,
  170.         CW_USEDEFAULT,
  171.         NULL,
  172.         NULL,
  173.         hInstance,
  174.         NULL
  175.     );
  176.  
  177.     if (!hwnd)
  178.         return (FALSE);
  179.  
  180.     GetClientRect(hwnd, (LPRECT) &Rect);
  181.  
  182.     /* Create a child window */
  183.  
  184.     hEditWnd = CreateWindow("Edit",
  185.         NULL,
  186.         WS_CHILD | WS_VISIBLE |
  187.         ES_MULTILINE |
  188.         WS_VSCROLL | WS_HSCROLL |
  189.         ES_AUTOHSCROLL | ES_AUTOVSCROLL,
  190.         0,
  191.         0,
  192.         (Rect.right-Rect.left),
  193.         (Rect.bottom-Rect.top),
  194.         hwnd,
  195.         IDC_EDIT,                          /* Child control i.d. */
  196.         hInst,
  197.         NULL);
  198.  
  199.     if (!hEditWnd) {
  200.         DestroyWindow(hwnd);
  201.         return (NULL);
  202.     }
  203.  
  204.     /* Get an hourglass cursor to use during file transfers */
  205.  
  206.     hHourGlass = LoadCursor(NULL, IDC_WAIT);
  207.     
  208.     ShowWindow(hwnd, nCmdShow);
  209.     UpdateWindow(hwnd);
  210.     return (TRUE);
  211.  
  212. }
  213.  
  214. /****************************************************************************
  215.  
  216.     FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
  217.  
  218.     PURPOSE:  Processes messages
  219.  
  220.     MESSAGES:
  221.  
  222.         WM_COMMAND    - application menu (About dialog box)
  223.         WM_DESTROY    - destroy window
  224.         WM_SIZE       - window size has changed
  225.         WM_QUERYENDSESSION - willing to end session?
  226.         WM_ENDSESSION - end Windows session
  227.         WM_CLOSE      - close the window
  228.         WM_SIZE       - window resized
  229.  
  230.     COMMENTS:
  231.  
  232.         Adds printing capability to the EDITFILE program.  Printing request
  233.         is sent as an IDM_PRINT message.
  234.  
  235.         Before the printing operation begins, a modeless dialog box is
  236.         created to allow the user to abort the printing operation.  This
  237.         dialog box remains active until the print job is completed, or the
  238.         user cancels the print operation.
  239.  
  240. ****************************************************************************/
  241.  
  242. long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
  243. HWND hWnd;
  244. unsigned message;
  245. WORD wParam;
  246. LONG lParam;
  247. {
  248.     FARPROC lpProcAbout, lpOpenDlg, lpSaveAsDlg;
  249.  
  250.     int Success;                            /* return value from SaveAsDlg() */
  251.     int IOStatus;                /* result of file i/o      */
  252.     int nPageSize;                /* vert. resolution of printer device */
  253.  
  254.  
  255.     switch (message) {
  256.         case WM_COMMAND:
  257.             switch (wParam) {
  258.                 case IDM_ABOUT:
  259.                     lpProcAbout = MakeProcInstance(About, hInst);
  260.                     DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);
  261.                     FreeProcInstance(lpProcAbout);
  262.                     break;
  263.  
  264.                 case IDM_NEW:
  265.  
  266.                     /* If current file has been modified, query user about
  267.                      * saving it.
  268.                      */
  269.  
  270.                     if (!QuerySaveFile(hWnd))
  271.                         return (NULL);
  272.  
  273.                     /* bChanges is set to FALSE to indicate there have been
  274.                      * no changes since the last file save.
  275.                      */
  276.  
  277.                     bChanges = FALSE;
  278.                     FileName[0] = 0;
  279.  
  280.                     /* Update the edit buffer */
  281.  
  282.                     SetNewBuffer(hWnd, NULL, Untitled);
  283.                     break;
  284.  
  285.                 case IDM_OPEN:
  286.                     if (!QuerySaveFile(hWnd))
  287.                         return (NULL);
  288.  
  289.                     lpOpenDlg = MakeProcInstance((FARPROC) OpenDlg, hInst);
  290.  
  291.                     /* Open the file and get its handle */
  292.  
  293.                     hFile = DialogBox(hInst, "Open", hWnd, lpOpenDlg);
  294.                     FreeProcInstance(lpOpenDlg);
  295.                     if (!hFile)
  296.                         return (NULL);
  297.  
  298.                     /* Allocate edit buffer to the size of the file + 1 */
  299.  
  300.                     hEditBuffer =
  301.                         LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,
  302.                 (WORD)FileStatus.st_size+1);
  303.  
  304.                     if (!hEditBuffer) {
  305.                         MessageBox(hWnd, "Not enough memory.",
  306.                             NULL, MB_OK | MB_ICONHAND);
  307.                         return (NULL);
  308.                     }
  309.                     hSaveCursor = SetCursor(hHourGlass);
  310.                     pEditBuffer = LocalLock(hEditBuffer);
  311.  
  312.                     IOStatus = read(hFile, pEditBuffer, FileStatus.st_size);
  313.                     close(hFile);
  314.  
  315.                     /* # bytes read must equal file size */
  316.  
  317.                     if (IOStatus != (int)FileStatus.st_size) {
  318.  
  319.                         sprintf(str, "Error reading %s.", FileName);
  320.                         SetCursor(hSaveCursor);      /* Remove the hourglass */
  321.                         MessageBox(hWnd, str, NULL, MB_OK | MB_ICONEXCLAMATION);
  322.                     }
  323.  
  324.                     LocalUnlock(hEditBuffer);
  325.  
  326.                     /* Set up a new buffer and window title */
  327.  
  328.                     sprintf(str, "PrntFile - %s", FileName);
  329.                     SetNewBuffer(hWnd, hEditBuffer, str);
  330.                     SetCursor(hSaveCursor);            /* restore the cursor */
  331.                     break;
  332.  
  333.                 case IDM_SAVE:
  334.  
  335.                     /* If there is no filename, use the saveas command to get
  336.                      * one.  Otherwise, save the file using the current
  337.                      * filename.
  338.                      */
  339.  
  340.                     if (!FileName[0])
  341.                         goto saveas;
  342.                     if (bChanges)
  343.                         SaveFile(hWnd);
  344.                     break;
  345.  
  346.                 case IDM_SAVEAS:
  347. saveas:
  348.                     lpSaveAsDlg = MakeProcInstance(SaveAsDlg, hInst);
  349.  
  350.                     /* Call the SaveAsDlg() function to get the new filename */
  351.  
  352.                     Success = DialogBox(hInst, "SaveAs", hWnd, lpSaveAsDlg);
  353.                     FreeProcInstance(lpSaveAsDlg);
  354.  
  355.                     /* If successful, update the window title, save the file */
  356.  
  357.                     if (Success == IDOK) {
  358.                         sprintf(str, "PrntFile - %s", FileName);
  359.                         SetWindowText(hWnd, str);
  360.                         SaveFile(hWnd);
  361.                     }
  362.                     break;                                  /* User canceled */
  363.                 case IDM_PRINT:
  364.                     hSaveCursor = SetCursor(hHourGlass);
  365.                     hPr = GetPrinterDC();
  366.                     if (!hPr) {
  367.                         sprintf(str, "Cannot print %s", FileName);
  368.                         MessageBox(hWnd, str, NULL, MB_OK | MB_ICONHAND);
  369.                         return (NULL);
  370.                     }
  371.  
  372.                     lpAbortDlg =  MakeProcInstance(AbortDlg, hInst);
  373.                     lpAbortProc = MakeProcInstance(AbortProc, hInst);
  374.  
  375.                     /* Define the abort function */
  376.  
  377.                     Escape(hPr, SETABORTPROC, NULL,
  378.                         (LPSTR) (long) lpAbortProc,
  379.                         (LPSTR) NULL);
  380.  
  381.                     if (Escape(hPr, STARTDOC, 4, "PrntFile text",
  382.                             (LPSTR) NULL) < 0) {
  383.                         MessageBox(hWnd, "Unable to start print job",
  384.                             NULL, MB_OK | MB_ICONHAND);
  385.                         FreeProcInstance(lpAbortDlg);
  386.                         FreeProcInstance(lpAbortProc);
  387.                         DeleteDC(hPr);
  388.                     }
  389.  
  390.                     bAbort = FALSE; /* Clears the abort flag  */
  391.  
  392.                     /* Create the Abort dialog box (modeless) */
  393.  
  394.                     hAbortDlgWnd = CreateDialog(hInst, "AbortDlg",
  395.                         hWnd, lpAbortDlg);
  396.  
  397.                     if (!hAbortDlgWnd) {
  398.                         SetCursor(hSaveCursor);      /* Remove the hourglass */
  399.                         MessageBox(hWnd, "NULL Abort window handle",
  400.                             NULL, MB_OK | MB_ICONHAND);
  401.                         return (FALSE);
  402.                     }
  403.                     
  404.                     /* Now show Abort dialog */
  405.  
  406.                     ShowWindow (hAbortDlgWnd, SW_NORMAL);
  407.  
  408.                     /* Disable the main window to avoid reentrancy problems */
  409.  
  410.                     EnableWindow(hWnd, FALSE);
  411.                     SetCursor(hSaveCursor);      /* Remove the hourglass */
  412.  
  413.                     /* Since you may have more than one line, you need to
  414.                      * compute the spacing between lines.  You can do that by
  415.                      * retrieving the height of the characters you are printing
  416.                      * and advancing their height plus the recommended external
  417.                      * leading height.
  418.                      */
  419.  
  420.                     GetTextMetrics(hPr, &TextMetric);
  421.                     LineSpace = TextMetric.tmHeight +
  422.                         TextMetric.tmExternalLeading;
  423.  
  424.                     /* Since you may have more lines than can fit on one
  425.                      * page, you need to compute the number of lines you can
  426.                      * print per page.  You can do that by retrieving the
  427.              * dimensions of the page and dividing the height
  428.                      * by the line spacing.
  429.                      */
  430.  
  431.             nPageSize = GetDeviceCaps (hPr, VERTRES);
  432.             LinesPerPage = nPageSize / LineSpace - 1;
  433.  
  434.  
  435.                     /* You can output only one line at a time, so you need a
  436.                      * count of the number of lines to print.  You can retrieve
  437.                      * the count sending the EM_GETLINECOUNT message to the edit
  438.                      * control.
  439.                      */
  440.  
  441.                     dwLines = SendMessage(hEditWnd, EM_GETLINECOUNT, 0, 0L);
  442.  
  443.                     /* Keep track of the current line on the current page */
  444.  
  445.                     CurrentLine = 1;
  446.  
  447.                     /* One way to output one line at a time is to retrieve
  448.                      * one line at a time from the edit control and write it
  449.                      * using the TextOut function.  For each line you need to
  450.                      * advance one line space.  Also, you need to check for the
  451.                      * end of the page and start a new page if necessary.
  452.                      */
  453.  
  454.                     for (dwIndex = IOStatus = 0; dwIndex < dwLines; dwIndex++) {
  455.                         pLine[0] = 128;               /* Maximum buffer size */
  456.                         pLine[1] = 0;
  457.                         LineLength = SendMessage(hEditWnd, EM_GETLINE,
  458.                             (WORD)dwIndex, (LONG)((LPSTR)pLine));
  459.                         TextOut(hPr, 0, CurrentLine*LineSpace,
  460.                             (LPSTR)pLine, LineLength);
  461.                         if (++CurrentLine > LinesPerPage ) {
  462.                             CurrentLine = 1;
  463.                             IOStatus = Escape(hPr, NEWFRAME, 0, 0L, 0L);
  464.                             if (IOStatus<0 || bAbort)
  465.                                 break;
  466.                         }
  467.                     }
  468.  
  469.                     if (IOStatus >= 0 && !bAbort) {
  470.                         Escape(hPr, NEWFRAME, 0, 0L, 0L);
  471.                         Escape(hPr, ENDDOC, 0, 0L, 0L);
  472.                     }
  473.                     EnableWindow(hWnd, TRUE);
  474.  
  475.                     /* Destroy the Abort dialog box */
  476.  
  477.                     DestroyWindow(hAbortDlgWnd);
  478.                     FreeProcInstance(lpAbortDlg);
  479.                     FreeProcInstance(lpAbortProc);
  480.                     DeleteDC(hPr);
  481.                     break;
  482.  
  483.  
  484.                 /* edit menu commands */
  485.  
  486.                 case IDM_UNDO:
  487.                 case IDM_CUT:
  488.                 case IDM_COPY:
  489.                 case IDM_PASTE:
  490.                 case IDM_CLEAR:
  491.                     MessageBox (
  492.                           GetFocus(),
  493.                           "Command not implemented",
  494.                           "PrntFile Sample Application",
  495.                           MB_ICONASTERISK | MB_OK);
  496.                     break;  
  497.  
  498.                 case IDM_EXIT:
  499.                     QuerySaveFile(hWnd);
  500.                     DestroyWindow(hWnd);
  501.                     break;
  502.  
  503.                 case IDC_EDIT:
  504.                     if (HIWORD (lParam) == EN_ERRSPACE) {
  505.                         MessageBox (
  506.                               GetFocus ()
  507.                             , "Out of memory."
  508.                             , "PrntFile Sample Application"
  509.                             , MB_ICONHAND | MB_OK
  510.                         );
  511.                     }
  512.                     break;
  513.  
  514.             } 
  515.             break;
  516.  
  517.         case WM_SETFOCUS:
  518.             SetFocus (hEditWnd);
  519.             break;
  520.  
  521.         case WM_SIZE:
  522.             MoveWindow(hEditWnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  523.             break;
  524.  
  525.         case WM_QUERYENDSESSION:             /* message: to end the session? */
  526.             return (QuerySaveFile(hWnd));
  527.  
  528.         case WM_CLOSE:                       /* message: close the window    */
  529.             if (QuerySaveFile(hWnd))
  530.                 DestroyWindow(hWnd);
  531.             break;
  532.  
  533.         case WM_DESTROY:
  534.             PostQuitMessage(0);
  535.             break;
  536.  
  537.         default:
  538.             return (DefWindowProc(hWnd, message, wParam, lParam));
  539.     }
  540.     return (NULL);
  541. }
  542.  
  543. /****************************************************************************
  544.  
  545.     FUNCTION: SaveAsDlg(HWND, unsigned, WORD, LONG)
  546.  
  547.     PURPOSE: Allows user to change name to save file to
  548.  
  549.     COMMENTS:
  550.  
  551.         This will initialize the window class if it is the first time this
  552.         application is run.  It then creates the window, and processes the
  553.         message loop until a PostQuitMessage is received.  It exits the
  554.         application by returning the value passed by the PostQuitMessage.
  555.  
  556. ****************************************************************************/
  557.  
  558. int FAR PASCAL SaveAsDlg(hDlg, message, wParam, lParam)
  559. HWND hDlg;
  560. unsigned message;
  561. WORD wParam;
  562. LONG lParam;
  563. {
  564.     char TempName[128];
  565.  
  566.     switch (message) {
  567.         case WM_INITDIALOG:
  568.  
  569.             /* If no filename is entered, don't allow the user to save to it */
  570.  
  571.             if (!FileName[0])
  572.                 bSaveEnabled = FALSE;
  573.             else {
  574.                 bSaveEnabled = TRUE;
  575.  
  576.                 /* Process the path to fit within the IDC_PATH field */
  577.  
  578.                 DlgDirList(hDlg, DefPath, NULL, IDC_PATH, 0x4010);
  579.  
  580.                 /* Send the current filename to the edit control */
  581.  
  582.                 SetDlgItemText(hDlg, IDC_EDIT, FileName);
  583.  
  584.                 /* Accept all characters in the edit control */
  585.  
  586.                 SendDlgItemMessage(hDlg, IDC_EDIT, EM_SETSEL, 0,
  587.                     MAKELONG(0, 0x7fff));
  588.             }
  589.  
  590.             /* Enable or disable the save control depending on whether the
  591.              * filename exists.
  592.              */
  593.  
  594.             EnableWindow(GetDlgItem(hDlg, IDOK), bSaveEnabled);
  595.  
  596.             /* Set the focus to the edit control within the dialog box */
  597.  
  598.             SetFocus(GetDlgItem(hDlg, IDC_EDIT));
  599.             return (FALSE);                 /* FALSE since Focus was changed */
  600.  
  601.         case WM_COMMAND:
  602.             switch (wParam) {
  603.                 case IDC_EDIT:
  604.  
  605.                     /* If there was previously no filename in the edit
  606.                      * control, then the save control must be enabled as soon as
  607.                      * a character is entered.
  608.                      */
  609.  
  610.                     if (HIWORD(lParam) == EN_CHANGE && !bSaveEnabled)
  611.                     EnableWindow(GetDlgItem(hDlg, IDOK), bSaveEnabled = TRUE);
  612.                     return (TRUE);
  613.  
  614.                 case IDOK:
  615.  
  616.                    /* Get the filename from the edit control */
  617.  
  618.                     GetDlgItemText(hDlg, IDC_EDIT, TempName, 128);
  619.  
  620.                     /* If there are no wildcards, then separate the name into
  621.                      * path and name.  If a path was specified, replace the
  622.                      * default path with the new path.
  623.                      */
  624.  
  625.                     if (CheckFileName(hDlg, FileName, TempName)) {
  626.                         SeparateFile(hDlg, (LPSTR) str, (LPSTR) DefSpec,
  627.                             (LPSTR) FileName);
  628.                         if (str[0])
  629.                             strcpy(DefPath, str);
  630.  
  631.                         /* Tell the caller a filename was selected */
  632.  
  633.                         EndDialog(hDlg, IDOK);
  634.                     }
  635.                     return (TRUE);
  636.  
  637.                 case IDCANCEL:
  638.  
  639.                     /* Tell the caller the user canceled the SaveAs function */
  640.  
  641.                     EndDialog(hDlg, IDCANCEL);
  642.                     return (TRUE);
  643.             }
  644.             break;
  645.  
  646.     }
  647.     return (FALSE);
  648. }
  649.  
  650. /****************************************************************************
  651.  
  652.     FUNCTION: OpenDlg(HWND, unsigned, WORD, LONG)
  653.  
  654.     PURPOSE: Let user select a file, and open it.
  655.  
  656. ****************************************************************************/
  657.  
  658. HANDLE FAR PASCAL OpenDlg(hDlg, message, wParam, lParam)
  659. HWND hDlg;
  660. unsigned message;
  661. WORD wParam;
  662. LONG lParam;
  663. {
  664.     WORD index;
  665.     PSTR pTptr;
  666.     HANDLE hFile;
  667.  
  668.     switch (message) {
  669.         case WM_COMMAND:
  670.             switch (wParam) {
  671.  
  672.                 case IDC_LISTBOX:
  673.                     switch (HIWORD(lParam)) {
  674.  
  675.                         case LBN_SELCHANGE:
  676.                             /* If item is a directory name, append "*.*" */
  677.                 if (DlgDirSelect(hDlg, str, IDC_LISTBOX)) {
  678.                                 strcat(str, DefSpec);
  679.  
  680.                 }
  681.                             SetDlgItemText(hDlg, IDC_EDIT, str);
  682.                             SendDlgItemMessage(hDlg,
  683.                                 IDC_EDIT,
  684.                                 EM_SETSEL,
  685.                                 NULL,
  686.                                 MAKELONG(0, 0x7fff));
  687.  
  688.  
  689.                             break;
  690.  
  691.                         case LBN_DBLCLK:
  692.                             goto openfile;
  693.                     }
  694.                     return (TRUE);
  695.  
  696.                 case IDOK:
  697. openfile:
  698.                     GetDlgItemText(hDlg, IDC_EDIT, OpenName, 128);
  699.                     if (strchr(OpenName, '*') || strchr(OpenName, '?')) {
  700.                         SeparateFile(hDlg, (LPSTR) str, (LPSTR) DefSpec,
  701.                             (LPSTR) OpenName);
  702.                         if (str[0])
  703.                             strcpy(DefPath, str);
  704.                         ChangeDefExt(DefExt, DefSpec);
  705.                         UpdateListBox(hDlg);
  706.                         return (TRUE);
  707.                     }
  708.  
  709.                     if (!OpenName[0]) {
  710.                         MessageBox(hDlg, "No filename specified.",
  711.                             NULL, MB_OK | MB_ICONHAND);
  712.                         return (TRUE);
  713.                     }
  714.  
  715.                     AddExt(OpenName, DefExt);
  716.  
  717.                     /* Open the file */
  718.  
  719.                     if ((hFile = OpenFile(OpenName, (LPOFSTRUCT) &OfStruct,
  720.                             OF_READ)) == -1) {
  721.                         sprintf(str, "Error %d opening %s.",
  722.                             OfStruct.nErrCode, OpenName);
  723.                         MessageBox(hDlg, str, NULL,
  724.                             MB_OK | MB_ICONHAND);
  725.                     }
  726.                     else {
  727.  
  728.                         /* Make sure there's enough room for the file */
  729.  
  730.                         fstat(hFile, &FileStatus);
  731.  
  732.                         if (FileStatus.st_size > MAXFILESIZE) {
  733.                             sprintf(str,
  734.                     "Not enough memory to load %s.\n%s exceeds %ld bytes.",
  735.                                 OpenName, OpenName, MAXFILESIZE);
  736.                             MessageBox(hDlg, str, NULL,
  737.                                 MB_OK | MB_ICONHAND);
  738.                             return (TRUE);
  739.                         }
  740.  
  741.                         /* File is opened and there is enough room so return
  742.                          * the handle to the caller.
  743.                          */
  744.  
  745.                         strcpy(FileName, OpenName);
  746.                         EndDialog(hDlg, hFile);
  747.                         return (TRUE);
  748.                     }
  749.                     return (TRUE);
  750.  
  751.                 case IDCANCEL:
  752.            /* strcpy(DefPath, str);
  753.             ChangeDefExt(DefExt, DefSpec);*/
  754.                     EndDialog(hDlg, NULL);
  755.                     return (TRUE);
  756.             }
  757.             break;
  758.  
  759.         case WM_INITDIALOG:                        /* message: initialize    */
  760.             UpdateListBox(hDlg);
  761.             SetDlgItemText(hDlg, IDC_EDIT, DefSpec);
  762.             SendDlgItemMessage(hDlg,               /* dialog handle      */
  763.                 IDC_EDIT,                          /* where to send message  */
  764.                 EM_SETSEL,                         /* select characters      */
  765.                 NULL,                              /* additional information */
  766.                 MAKELONG(0, 0x7fff));              /* entire contents      */
  767.             SetFocus(GetDlgItem(hDlg, IDC_EDIT));
  768.             return (FALSE); /* Indicates the focus is set to a control */
  769.     }
  770.     return FALSE;
  771. }
  772.  
  773. /****************************************************************************
  774.  
  775.     FUNCTION: UpdateListBox(HWND);
  776.  
  777.     PURPOSE: Update the list box of OpenDlg
  778.  
  779. ****************************************************************************/
  780.  
  781. void UpdateListBox(hDlg)
  782. HWND hDlg;
  783. {
  784.     strcpy(str, DefPath);
  785.     strcat(str, DefSpec);
  786.     DlgDirList(hDlg, str, IDC_LISTBOX, IDC_PATH, 0x4010);
  787.  
  788.     /* To ensure that the listing is made for a subdir. of
  789.      * current drive dir...
  790.      */
  791.     if (!strchr (DefPath, ':'))
  792.     DlgDirList(hDlg, DefSpec, IDC_LISTBOX, IDC_PATH, 0x4010);
  793.  
  794.     /* Remove the '..' character from path if it exists, since this
  795.      * will make DlgDirList move us up an additional level in the tree
  796.      * when UpdateListBox() is called again.
  797.      */
  798.     if (strstr (DefPath, ".."))
  799.     DefPath[0] = '\0';
  800.     SetDlgItemText(hDlg, IDC_EDIT, DefSpec);
  801. }
  802.  
  803. /****************************************************************************
  804.  
  805.     FUNCTION: ChangeDefExt(PSTR, PSTR);
  806.  
  807.     PURPOSE: Change the default extension
  808.  
  809. ****************************************************************************/
  810.  
  811. void ChangeDefExt(Ext, Name)
  812. PSTR Ext, Name;
  813. {
  814.     PSTR pTptr;
  815.  
  816.     pTptr = Name;
  817.     while (*pTptr && *pTptr != '.')
  818.         pTptr++;
  819.     if (*pTptr)
  820.         if (!strchr(pTptr, '*') && !strchr(pTptr, '?'))
  821.             strcpy(Ext, pTptr);
  822. }
  823.  
  824. /****************************************************************************
  825.  
  826.     FUNCTION: SeparateFile(HWND, LPSTR, LPSTR, LPSTR)
  827.  
  828.     PURPOSE: Separate filename and pathname
  829.  
  830. ****************************************************************************/
  831.  
  832. void SeparateFile(hDlg, lpDestPath, lpDestFileName, lpSrcFileName)
  833. HWND hDlg;
  834. LPSTR lpDestPath, lpDestFileName, lpSrcFileName;
  835. {
  836.     LPSTR lpTmp;
  837.     char  cTmp;
  838.  
  839.     lpTmp = lpSrcFileName + (long) lstrlen(lpSrcFileName);
  840.     while (*lpTmp != ':' && *lpTmp != '\\' && lpTmp > lpSrcFileName)
  841.         lpTmp = AnsiPrev(lpSrcFileName, lpTmp);
  842.     if (*lpTmp != ':' && *lpTmp != '\\') {
  843.         lstrcpy(lpDestFileName, lpSrcFileName);
  844.         lpDestPath[0] = 0;
  845.         return;
  846.     }
  847.     lstrcpy(lpDestFileName, lpTmp + 1);
  848.     cTmp = *(lpTmp + 1);
  849.     lstrcpy(lpDestPath, lpSrcFileName);
  850.      *(lpTmp + 1) = cTmp;
  851.     lpDestPath[(lpTmp - lpSrcFileName) + 1] = 0;
  852. }
  853.  
  854. /****************************************************************************
  855.  
  856.     FUNCTION: AddExt(PSTR, PSTR);
  857.  
  858.     PURPOSE: Add default extension
  859.  
  860. /***************************************************************************/
  861.  
  862. void AddExt(Name, Ext)
  863. PSTR Name, Ext;
  864. {
  865.     PSTR pTptr;
  866.  
  867.     pTptr = Name;
  868.     while (*pTptr && *pTptr != '.')
  869.         pTptr++;
  870.     if (*pTptr != '.')
  871.         strcat(Name, Ext);
  872. }
  873.  
  874. /****************************************************************************
  875.  
  876.     FUNCTION: CheckFileName(HWND, PSTR, PSTR)
  877.  
  878.     PURPOSE: Check for wildcards, add extension if needed
  879.  
  880.     COMMENTS:
  881.  
  882.         Make sure you have a filename and that it does not contain any
  883.         wildcards.  If needed, add the default extension.  This function is
  884.         called whenever your application wants to save a file.
  885.  
  886. ****************************************************************************/
  887.  
  888. BOOL CheckFileName(hWnd, pDest, pSrc)
  889. HWND hWnd;
  890. PSTR pDest, pSrc;
  891. {
  892.     PSTR pTmp;
  893.  
  894.     if (!pSrc[0])
  895.         return (FALSE);               /* Indicates no filename was specified */
  896.  
  897.     pTmp = pSrc;
  898.     while (*pTmp) {                     /* Searches the string for wildcards */
  899.         switch (*pTmp++) {
  900.             case '*':
  901.             case '?':
  902.                 MessageBox(hWnd, "Wildcards not allowed.",
  903.                     NULL, MB_OK | MB_ICONEXCLAMATION);
  904.                 return (FALSE);
  905.         }
  906.     }
  907.  
  908.     AddExt(pSrc, DefExt);            /* Adds the default extension if needed */
  909.  
  910.     if (OpenFile(pSrc, (LPOFSTRUCT) &OfStruct, OF_EXIST) >= 0) {
  911.         sprintf(str, "Replace existing %s?", pSrc);
  912.         if (MessageBox(hWnd, str, "PrntFile",
  913.                 MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  914.             return (FALSE);
  915.     }
  916.     strcpy(pDest, pSrc);
  917.     return (TRUE);
  918. }
  919.  
  920. /****************************************************************************
  921.  
  922.     FUNCTION: SaveFile(HWND)
  923.  
  924.     PURPOSE: Save current file
  925.  
  926.     COMMENTS:
  927.  
  928.         This saves the current contents of the Edit buffer, and changes
  929.         bChanges to indicate that the buffer has not been changed since the
  930.         last save.
  931.  
  932.         Before the edit buffer is sent, you must get its handle and lock it
  933.         to get its address.  Once the file is written, you must unlock the
  934.         buffer.  This allows Windows to move the buffer when not in immediate
  935.         use.
  936.  
  937. ****************************************************************************/
  938.  
  939. BOOL SaveFile(hWnd)
  940. HWND hWnd;
  941. {
  942.     BOOL bSuccess;
  943.     int IOStatus;                                  /* result of a file write */
  944.  
  945.     if ((hFile = OpenFile(FileName, &OfStruct,
  946.         OF_PROMPT | OF_CANCEL | OF_CREATE)) < 0) {
  947.  
  948.         /* If the file can't be saved */
  949.  
  950.         sprintf(str, "Cannot write to %s.", FileName);
  951.         MessageBox(hWnd, str, NULL, MB_OK | MB_ICONHAND);
  952.         return (FALSE);
  953.     }
  954.  
  955.  
  956.     hEditBuffer = SendMessage(hEditWnd, EM_GETHANDLE, 0, 0L);
  957.     pEditBuffer = LocalLock(hEditBuffer);
  958.  
  959.     /* Set the cursor to an hourglass during the file transfer */
  960.  
  961.     hSaveCursor = SetCursor(hHourGlass);
  962.     IOStatus = write(hFile, pEditBuffer, strlen(pEditBuffer));
  963.     close(hFile);
  964.     SetCursor(hSaveCursor);
  965.     if (IOStatus != strlen(pEditBuffer)) {
  966.         sprintf(str, "Error writing to %s.", FileName);
  967.         MessageBox(hWnd, str,
  968.             NULL, MB_OK | MB_ICONHAND);
  969.         bSuccess = FALSE;
  970.     }
  971.     else {
  972.         bSuccess = TRUE;                /* Indicates the file was saved      */
  973.         bChanges = FALSE;               /* Indicates changes have been saved */
  974.     }
  975.  
  976.     LocalUnlock(hEditBuffer);
  977.     return (bSuccess);
  978. }
  979.  
  980. /****************************************************************************
  981.  
  982.     FUNCTION: QuerySaveFile(HWND);
  983.  
  984.     PURPOSE: Called when some action might lose current contents
  985.  
  986.     COMMENTS:
  987.  
  988.         This function is called whenever we are about to take an action that
  989.         would lose the current contents of the edit buffer.
  990.  
  991. ****************************************************************************/
  992.  
  993. BOOL QuerySaveFile(hWnd)
  994. HWND hWnd;
  995. {
  996.     int Response;
  997.     FARPROC lpSaveAsDlg;
  998.  
  999.     if (bChanges) {
  1000.         sprintf(str, "Save current changes: %s", FileName);
  1001.         Response = MessageBox(hWnd, str,
  1002.             "PrntFile",  MB_YESNOCANCEL | MB_ICONHAND);
  1003.         if (Response == IDYES) {
  1004. check_name:
  1005.  
  1006.             /* Make sure there is a filename to save to */
  1007.  
  1008.             if (!FileName[0]) {
  1009.                 lpSaveAsDlg = MakeProcInstance(SaveAsDlg, hInst);
  1010.                 Response = DialogBox(hInst, "SaveAs",
  1011.                     hWnd, lpSaveAsDlg);
  1012.                 FreeProcInstance(lpSaveAsDlg);
  1013.                 if (Response == IDOK)
  1014.                     goto check_name;
  1015.                 else
  1016.                     return (FALSE);
  1017.             }
  1018.             SaveFile(hWnd);
  1019.         }
  1020.         else if (Response == IDCANCEL)
  1021.             return (FALSE);
  1022.     }
  1023.     else
  1024.         return (TRUE);
  1025. }
  1026.  
  1027. /****************************************************************************
  1028.  
  1029.     FUNCTION: SetNewBuffer(HWND, HANDLE, PSTR)
  1030.  
  1031.     PURPOSE: Set new buffer for edit window
  1032.  
  1033.     COMMENTS:
  1034.  
  1035.         Point the edit window to the new buffer, update the window title, and
  1036.         redraw the edit window.  If hNewBuffer is NULL, then create an empty
  1037.         1K buffer, and return its handle.
  1038.  
  1039. ****************************************************************************/
  1040.  
  1041. void SetNewBuffer(hWnd, hNewBuffer, Title)
  1042. HWND hWnd;
  1043. HANDLE hNewBuffer;
  1044. PSTR Title;
  1045. {
  1046.     HANDLE hOldBuffer;
  1047.  
  1048.     hOldBuffer = SendMessage(hEditWnd, EM_GETHANDLE, 0, 0L);
  1049.     LocalFree(hOldBuffer);
  1050.     if (!hNewBuffer)                    /* Allocates a buffer if none exists */
  1051.         hNewBuffer = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, 1);
  1052.  
  1053.     SendMessage(hEditWnd, EM_SETHANDLE, hNewBuffer, 0L); /* Updates the buffer
  1054.                                 and displays new buffer */
  1055.     SetWindowText(hWnd, Title);
  1056.     SetFocus(hEditWnd);
  1057.     bChanges = FALSE;
  1058. }
  1059.  
  1060.  
  1061. /****************************************************************************
  1062.  
  1063.     FUNCTION: GetPrinterDC()
  1064.  
  1065.     PURPOSE:  Get hDc for current device on current output port according to
  1066.               info in WIN.INI.
  1067.  
  1068.     COMMENTS:
  1069.  
  1070.         Searches WIN.INI for information about what printer is connected, and
  1071.         if found, creates a DC for the printer.
  1072.  
  1073.         returns
  1074.             hDC > 0 if success
  1075.             hDC = 0 if failure
  1076.  
  1077. ****************************************************************************/
  1078.  
  1079. HANDLE GetPrinterDC()
  1080. {
  1081.     char pPrintInfo[80];
  1082.     LPSTR lpTemp;
  1083.     LPSTR lpPrintType;
  1084.     LPSTR lpPrintDriver;
  1085.     LPSTR lpPrintPort;
  1086.  
  1087.     if (!GetProfileString("windows", "Device", (LPSTR)"", pPrintInfo, 80))
  1088.         return (NULL);
  1089.     lpTemp = lpPrintType = pPrintInfo;
  1090.     lpPrintDriver = lpPrintPort = 0;
  1091.     while (*lpTemp) {
  1092.         if (*lpTemp == ',') {
  1093.             *lpTemp++ = 0;
  1094.             while (*lpTemp == ' ')
  1095.                 lpTemp = AnsiNext(lpTemp);
  1096.             if (!lpPrintDriver)
  1097.                 lpPrintDriver = lpTemp;
  1098.             else {
  1099.                 lpPrintPort = lpTemp;
  1100.                 break;
  1101.             }
  1102.         }
  1103.         else
  1104.             lpTemp = AnsiNext(lpTemp);
  1105.     }
  1106.  
  1107.     return (CreateDC(lpPrintDriver, lpPrintType, lpPrintPort, (LPSTR) NULL));
  1108. }
  1109.  
  1110. /****************************************************************************
  1111.  
  1112.     FUNCTION: AbortProc()
  1113.  
  1114.     PURPOSE:  Processes messages for the Abort Dialog box
  1115.  
  1116. ****************************************************************************/
  1117.  
  1118. int FAR PASCAL AbortProc(hPr, Code)
  1119. HDC hPr;                            /* for multiple printer display contexts */
  1120. int Code;                           /* printing status                */
  1121. {
  1122.     MSG msg;
  1123.  
  1124.     /* Process messages intended for the abort dialog box */
  1125.  
  1126.     while (!bAbort && PeekMessage(&msg, NULL, NULL, NULL, TRUE))
  1127.         if (!IsDialogMessage(hAbortDlgWnd, &msg)) {
  1128.             TranslateMessage(&msg);
  1129.             DispatchMessage(&msg);
  1130.         }
  1131.  
  1132.     /* bAbort is TRUE (return is FALSE) if the user has aborted */
  1133.  
  1134.     return (!bAbort);
  1135. }
  1136.  
  1137. /****************************************************************************
  1138.  
  1139.     FUNCTION: AbortDlg(HWND, unsigned, WORD, LONG)
  1140.  
  1141.     PURPOSE:  Processes messages for printer abort dialog box
  1142.  
  1143.     MESSAGES:
  1144.  
  1145.         WM_INITDIALOG - initialize dialog box
  1146.         WM_COMMAND    - Input received
  1147.  
  1148.     COMMENTS
  1149.  
  1150.         This dialog box is created while the program is printing, and allows
  1151.         the user to cancel the printing process.
  1152.  
  1153. ****************************************************************************/
  1154.  
  1155. int FAR PASCAL AbortDlg(hDlg, msg, wParam, lParam)
  1156. HWND hDlg;
  1157. unsigned msg;
  1158. WORD wParam;
  1159. LONG lParam;
  1160. {
  1161.     switch(msg) {
  1162.  
  1163.         /* Watch for Cancel button, RETURN key, ESCAPE key, or SPACE BAR */
  1164.  
  1165.         case WM_COMMAND:
  1166.             return (bAbort = TRUE);
  1167.  
  1168.         case WM_INITDIALOG:
  1169.  
  1170.             /* Set the focus to the Cancel box of the dialog */
  1171.  
  1172.             SetFocus(GetDlgItem(hDlg, IDCANCEL));
  1173.             SetDlgItemText(hDlg, IDC_FILENAME, FileName);
  1174.             return (TRUE);
  1175.         }
  1176.     return (FALSE);
  1177. }
  1178.  
  1179.  
  1180. /****************************************************************************
  1181.  
  1182.     FUNCTION: About(HWND, unsigned, WORD, LONG)
  1183.  
  1184.     PURPOSE:  Processes messages for "About" dialog box
  1185.  
  1186.     MESSAGES:
  1187.  
  1188.         WM_INITDIALOG - initialize dialog box
  1189.         WM_COMMAND    - Input received
  1190.  
  1191. ****************************************************************************/
  1192.  
  1193. BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
  1194. HWND hDlg;
  1195. unsigned message;
  1196. WORD wParam;
  1197. LONG lParam;
  1198. {
  1199.     switch (message) {
  1200.         case WM_INITDIALOG:
  1201.             return (TRUE);
  1202.  
  1203.         case WM_COMMAND:
  1204.         if (wParam == IDOK
  1205.                 || wParam == IDCANCEL) {
  1206.                 EndDialog(hDlg, TRUE);
  1207.                 return (TRUE);
  1208.             }
  1209.             return (TRUE);
  1210.     }
  1211.     return (FALSE);
  1212. }
  1213.