APP.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:49k
源码类别:

Windows编程

开发平台:

Visual C++

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  4. //  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  5. //  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
  6. //  A PARTICULAR PURPOSE.
  7. //
  8. //  Copyright (C) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  app.c
  13. //
  14. //  Description:
  15. //      This is a sample application that demonstrates how to use the
  16. //      Media Control Interface (MCI) in Windows. This application is
  17. //      also useful as an MCI device tester.
  18. //
  19. //  History:
  20. //      11/ 8/92    created.
  21. //
  22. //==========================================================================;
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. #include <mmsystem.h>
  26. #include <commdlg.h>
  27. #include <shellapi.h>
  28. #include <stdarg.h>
  29. #include <memory.h>
  30. #include "appport.h"
  31. #include "app.h"
  32. #include "mciapp.h"
  33. #include "debug.h"
  34. //
  35. //  globals, no less
  36. //
  37. HINSTANCE       ghinst;
  38. UINT            gfuAppOptions       = APP_OPTF_YIELDEXEC;
  39. TCHAR           gszAppSection[]     = TEXT("MCI App");
  40. TCHAR           gszNull[]           = TEXT("");
  41. TCHAR           gszAppName[APP_MAX_APP_NAME_CHARS];
  42. TCHAR           gszFileUntitled[APP_MAX_FILE_TITLE_CHARS];
  43. TCHAR           gszAppFileTitle[APP_MAX_FILE_TITLE_CHARS];
  44. TCHAR           gszAppFilePath[APP_MAX_FILE_PATH_CHARS];
  45. //==========================================================================;
  46. //
  47. //  Application helper functions
  48. //
  49. //
  50. //==========================================================================;
  51. //--------------------------------------------------------------------------;
  52. //
  53. //  int AppMsgBox
  54. //
  55. //  Description:
  56. //      This function displays a message for the application in a standard
  57. //      message box.
  58. //
  59. //      Note that this function takes any valid argument list that can
  60. //      be passed to wsprintf. Because of this, the application must
  61. //      remember to cast near string pointers to FAR when built for Win 16.
  62. //      You will get a nice GP fault if you do not cast them correctly.
  63. //
  64. //  Arguments:
  65. //      HWND hwnd: Handle to parent window for message box holding the
  66. //      message.
  67. //
  68. //      UINT fuStyle: Style flags for MessageBox().
  69. //
  70. //      PCTSTR pszFormat: Format string used for wvsprintf().
  71. //
  72. //  Return (int):
  73. //      The return value is the result of MessageBox() function.
  74. //
  75. //  History:
  76. //       2/13/93    created.
  77. //
  78. //--------------------------------------------------------------------------;
  79. int FNCGLOBAL AppMsgBox
  80. (
  81.     HWND            hwnd,
  82.     UINT            fuStyle,
  83.     PCTSTR          pszFormat,
  84.     ...
  85. )
  86. {
  87.     va_list     va;
  88.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  89.     int         n;
  90.     //
  91.     //  format and display the message..
  92.     //
  93.     va_start(va, pszFormat);
  94.     wvsprintf(ach, pszFormat, va);
  95.     va_end(va);
  96.     n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  97.     return (n);
  98. } // AppMsgBox()
  99. //--------------------------------------------------------------------------;
  100. //
  101. //  int AppMsgBoxId
  102. //
  103. //  Description:
  104. //      This function displays a message for the application. The message
  105. //      text is retrieved from the string resource table using LoadString.
  106. //
  107. //      Note that this function takes any valid argument list that can
  108. //      be passed to wsprintf. Because of this, the application must
  109. //      remember to cast near string pointers to FAR when built for Win 16.
  110. //      You will get a nice GP fault if you do not cast them correctly.
  111. //
  112. //  Arguments:
  113. //      HWND hwnd: Handle to parent window for message box holding the
  114. //      message.
  115. //
  116. //      UINT fuStyle: Style flags for MessageBox().
  117. //
  118. //      UINT uIdsFormat: String resource id to be loaded with LoadString()
  119. //      and used a the format string for wvsprintf().
  120. //
  121. //  Return (int):
  122. //      The return value is the result of MessageBox() if the string
  123. //      resource specified by uIdsFormat is valid. The return value is zero
  124. //      if the string resource failed to load.
  125. //
  126. //  History:
  127. //       2/13/93    created.
  128. //
  129. //--------------------------------------------------------------------------;
  130. int FNCGLOBAL AppMsgBoxId
  131. (
  132.     HWND            hwnd,
  133.     UINT            fuStyle,
  134.     UINT            uIdsFormat,
  135.     ...
  136. )
  137. {
  138.     va_list     va;
  139.     TCHAR       szFormat[APP_MAX_STRING_RC_CHARS];
  140.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  141.     int         n;
  142.     n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  143.     if (0 != n)
  144.     {
  145.         //
  146.         //  format and display the message..
  147.         //
  148.         va_start(va, uIdsFormat);
  149.         wvsprintf(ach, szFormat, va);
  150.         va_end(va);
  151.         n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  152.     }
  153.     return (n);
  154. } // AppMsgBoxId()
  155. //--------------------------------------------------------------------------;
  156. //
  157. //  void AppHourGlass
  158. //
  159. //  Description:
  160. //      This function changes the cursor to that of the hour glass or
  161. //      back to the previous cursor.
  162. //
  163. //      This function can be called recursively.
  164. //
  165. //  Arguments:
  166. //      BOOL fHourGlass: TRUE if we need the hour glass.  FALSE if we need
  167. //      the arrow back.
  168. //
  169. //  Return (void):
  170. //      On return, the cursor will be what was requested.
  171. //
  172. //  History:
  173. //      11/ 8/92    created.
  174. //
  175. //--------------------------------------------------------------------------;
  176. void FNGLOBAL AppHourGlass
  177. (
  178.     BOOL            fHourGlass
  179. )
  180. {
  181.     static HCURSOR  hcur;
  182.     static UINT     uWaiting = 0;
  183.     if (fHourGlass)
  184.     {
  185.         if (!uWaiting)
  186.         {
  187.             hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  188.             ShowCursor(TRUE);
  189.         }
  190.         uWaiting++;
  191.     }
  192.     else
  193.     {
  194.         --uWaiting;
  195.         if (!uWaiting)
  196.         {
  197.             ShowCursor(FALSE);
  198.             SetCursor(hcur);
  199.         }
  200.     }
  201. } // AppHourGlass()
  202. //--------------------------------------------------------------------------;
  203. //
  204. //  BOOL AppYield
  205. //
  206. //  Description:
  207. //      This function yields by dispatching all messages stacked up in the
  208. //      application queue.
  209. //
  210. //  Arguments:
  211. //      HWND hwnd: Handle to main window of application if not yielding
  212. //      for a dialog. Handle to dialog box if yielding for a dialog box.
  213. //
  214. //      BOOL fIsDialog: TRUE if being called to yield for a dialog box.
  215. //
  216. //  Return (BOOL):
  217. //      The return value is always TRUE.
  218. //
  219. //  History:
  220. //       2/ 7/93    created.
  221. //
  222. //--------------------------------------------------------------------------;
  223. BOOL FNGLOBAL AppYield
  224. (
  225.     HWND            hwnd,
  226.     BOOL            fIsDialog
  227. )
  228. {
  229.     MSG     msg;
  230.     if (fIsDialog)
  231.     {
  232.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  233.         {
  234.             if ((NULL == hwnd) || !IsDialogMessage(hwnd, &msg))
  235.             {
  236.                 //
  237.                 //  see comment below..
  238.                 //
  239.                 MciAppDispatchMessage(GetParent(hwnd), &msg);
  240.             }
  241.         }
  242.     }
  243.     else
  244.     {
  245.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  246.         {
  247.             //
  248.             //  normally, we would only do the following here:
  249.             //
  250.             //      TranslateMessage(&msg);
  251.             //      DispatchMessage(&msg);
  252.             //
  253.             //  but this app is special, so dispatch messages in a
  254.             //  special way...
  255.             //
  256.             MciAppDispatchMessage(hwnd, &msg);
  257.         }
  258.     }
  259.     return (TRUE);
  260. } // AppYield()
  261. //--------------------------------------------------------------------------;
  262. //
  263. //  int AppSetWindowText
  264. //
  265. //  Description:
  266. //      This function formats a string and sets the specified window text
  267. //      to the result.
  268. //
  269. //  Arguments:
  270. //      HWND hwnd: Handle to window to receive the new text.
  271. //
  272. //      PCTSTR pszFormat: Pointer to any valid format for wsprintf.
  273. //
  274. //  Return (int):
  275. //      The return value is the number of bytes that the resulting window
  276. //      text was.
  277. //
  278. //  History:
  279. //       2/ 7/93    created.
  280. //
  281. //--------------------------------------------------------------------------;
  282. int FNCGLOBAL AppSetWindowText
  283. (
  284.     HWND            hwnd,
  285.     PCTSTR          pszFormat,
  286.     ...
  287. )
  288. {
  289.     va_list     va;
  290.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  291.     int         n;
  292.     //
  293.     //  format and display the string in the window...
  294.     //
  295.     va_start(va, pszFormat);
  296.     n = wvsprintf(ach, pszFormat, va);
  297.     va_end(va);
  298.     SetWindowText(hwnd, ach);
  299.     return (n);
  300. } // AppSetWindowText()
  301. //--------------------------------------------------------------------------;
  302. //
  303. //  int AppSetWindowTextId
  304. //
  305. //  Description:
  306. //      This function formats a string and sets the specified window text
  307. //      to the result. The format string is extracted from the string
  308. //      table using LoadString() on the uIdsFormat argument.
  309. //
  310. //  Arguments:
  311. //      HWND hwnd: Handle to window to receive the new text.
  312. //
  313. //      UINT uIdsFormat: String resource id to be loaded with LoadString()
  314. //      and used a the format string for wvsprintf().
  315. //
  316. //  Return (int):
  317. //      The return value is the number of bytes that the resulting window
  318. //      text was. This value is zero if the LoadString() function fails
  319. //      for the uIdsFormat argument.
  320. //
  321. //  History:
  322. //       2/ 7/93    created.
  323. //
  324. //--------------------------------------------------------------------------;
  325. int FNCGLOBAL AppSetWindowTextId
  326. (
  327.     HWND            hwnd,
  328.     UINT            uIdsFormat,
  329.     ...
  330. )
  331. {
  332.     va_list     va;
  333.     TCHAR       szFormat[APP_MAX_STRING_RC_CHARS];
  334.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  335.     int         n;
  336.     n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  337.     if (0 != n)
  338.     {
  339.         //
  340.         //  format and display the string in the window...
  341.         //
  342.         va_start(va, uIdsFormat);
  343.         n = wvsprintf(ach, szFormat, va);
  344.         va_end(va);
  345.         SetWindowText(hwnd, ach);
  346.     }
  347.     return (n);
  348. } // AppSetWindowTextId()
  349. //--------------------------------------------------------------------------;
  350. //
  351. //  BOOL AppGetFileTitle
  352. //
  353. //  Description:
  354. //      This function extracts the file title from a file path and returns
  355. //      it in the caller's specified buffer.
  356. //
  357. //  Arguments:
  358. //      PCTSTR pszFilePath: Pointer to null terminated file path.
  359. //
  360. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  361. //
  362. //  Return (BOOL):
  363. //      Always returns TRUE. But should return FALSE if this function
  364. //      checked for bogus values, etc.
  365. //
  366. //  History:
  367. //       2/ 6/93    created.
  368. //
  369. //--------------------------------------------------------------------------;
  370. BOOL FNGLOBAL AppGetFileTitle
  371. (
  372.     PCTSTR          pszFilePath,
  373.     PTSTR           pszFileTitle
  374. )
  375. {
  376.     #define IS_SLASH(c)     ('/' == (c) || '\' == (c))
  377.     PTSTR       pch;
  378.     //
  379.     //  scan to the end of the file path string..
  380.     //
  381.     for (pch = pszFilePath; '' != *pch; pch++)
  382.         ;
  383.     //
  384.     //  now scan back toward the beginning of the string until a slash (),
  385.     //  colon, or start of the string is encountered.
  386.     //
  387.     while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch))
  388.     {
  389.         pch--;
  390.     }
  391.     //
  392.     //  finally, copy the 'title' into the destination buffer.. skip ahead
  393.     //  one char since the above loop steps back one too many chars...
  394.     //
  395.     lstrcpy(pszFileTitle, ++pch);
  396.     return (TRUE);
  397. } // AppGetFileTitle()
  398. //--------------------------------------------------------------------------;
  399. //
  400. //  BOOL AppGetFileName
  401. //
  402. //  Description:
  403. //      This function is a wrapper for the Get[Open/Save]FileName commdlg
  404. //      chooser dialogs. Based on the fuFlags argument, this function will
  405. //      display the appropriate chooser dialog and return the result.
  406. //
  407. //  Arguments:
  408. //      HWND hwnd: Handle to parent window for chooser dialog.
  409. //
  410. //      PTSTR pszFilePath: Pointer to buffer to receive the file path.
  411. //
  412. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  413. //      This argument may be NULL, in which case no title will be returned.
  414. //
  415. //      UINT fuFlags:
  416. //
  417. //  Return (BOOL):
  418. //      The return value is TRUE if a file was chosen. It is FALSE if the
  419. //      user canceled the operation.
  420. //
  421. //  History:
  422. //       2/ 6/93    created.
  423. //
  424. //--------------------------------------------------------------------------;
  425. BOOL FNGLOBAL AppGetFileName
  426. (
  427.     HWND            hwnd,
  428.     PTSTR           pszFilePath,
  429.     PTSTR           pszFileTitle,
  430.     UINT            fuFlags
  431. )
  432. {
  433.     #define APP_OFN_FLAGS_SAVE  (OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT)
  434.     #define APP_OFN_FLAGS_OPEN  (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST)
  435.     TCHAR           szExtDefault[APP_MAX_EXT_DEFAULT_CHARS];
  436.     TCHAR           szExtFilter[APP_MAX_EXT_FILTER_CHARS];
  437.     OPENFILENAME    ofn;
  438.     BOOL            f;
  439.     PTCHAR          pch;
  440.     //
  441.     //  get the extension filter and default extension for this application
  442.     //
  443.     LoadString(ghinst, IDS_OFN_EXT_DEF, szExtDefault, SIZEOF(szExtDefault));
  444.     LoadString(ghinst, IDS_OFN_EXT_FILTER, szExtFilter, SIZEOF(szExtFilter));
  445.     //
  446.     //  NOTE! building the filter string for the OPENFILENAME structure
  447.     //  is a bit more difficult when dealing with Unicode and C8's new
  448.     //  optimizer. it joyfully removes literal '' characters from
  449.     //  strings that are concatted together. if you try making each
  450.     //  string separate (array of pointers to strings), the compiler
  451.     //  will dword align them... etc, etc.
  452.     //
  453.     //  if you can think of a better way to build the silly filter string
  454.     //  for common dialogs and still work in Win 16 and Win 32 [Unicode]
  455.     //  i'd sure like to hear about it...
  456.     //
  457.     for (pch = &szExtFilter[0]; '' != *pch; pch++)
  458.     {
  459.         if ('!' == *pch)
  460.             *pch = '';
  461.     }
  462.     //
  463.     //  initialize the OPENFILENAME members
  464.     //
  465.     memset(&ofn, 0, sizeof(OPENFILENAME));
  466.     pszFilePath[0]          = '';
  467.     if (pszFileTitle)
  468.         pszFileTitle[0]     = '';
  469.     ofn.lStructSize         = sizeof(OPENFILENAME);
  470.     ofn.hwndOwner           = hwnd;
  471.     ofn.lpstrFilter         = szExtFilter;
  472.     ofn.lpstrCustomFilter   = NULL;
  473.     ofn.nMaxCustFilter      = 0L;
  474.     ofn.nFilterIndex        = 1L;
  475.     ofn.lpstrFile           = pszFilePath;
  476.     ofn.nMaxFile            = APP_MAX_FILE_PATH_CHARS;
  477.     ofn.lpstrFileTitle      = pszFileTitle;
  478.     ofn.nMaxFileTitle       = pszFileTitle ? APP_MAX_FILE_TITLE_CHARS : 0;
  479.     ofn.lpstrInitialDir     = NULL;
  480.     ofn.nFileOffset         = 0;
  481.     ofn.nFileExtension      = 0;
  482.     ofn.lpstrDefExt         = szExtDefault;
  483.     //
  484.     //  if the fuFlags.APP_GFNF_SAVE bit is set, then call GetSaveFileName()
  485.     //  otherwise call GetOpenFileName(). why commdlg was designed with
  486.     //  two separate functions for save and open only clark knows.
  487.     //
  488.     if (fuFlags & APP_GFNF_SAVE)
  489.     {
  490.         ofn.Flags = APP_OFN_FLAGS_SAVE;
  491.         f = GetSaveFileName(&ofn);
  492.     }
  493.     else
  494.     {
  495.         ofn.Flags = APP_OFN_FLAGS_OPEN;
  496.         f = GetOpenFileName(&ofn);
  497.     }
  498.     return (f);
  499. } // AppGetFileName()
  500. //--------------------------------------------------------------------------;
  501. //
  502. //  BOOL AppTitle
  503. //
  504. //  Description:
  505. //      This function formats and sets the title text of the application's
  506. //      window.
  507. //
  508. //  Arguments:
  509. //      HWND hwnd: Handle to application window to set title text for.
  510. //
  511. //      PCTSTR pszFileTitle: Pointer to file title to display.
  512. //
  513. //  Return (BOOL):
  514. //      The return value is always TRUE.
  515. //
  516. //  History:
  517. //       2/ 6/93    created.
  518. //
  519. //--------------------------------------------------------------------------;
  520. BOOL FNGLOBAL AppTitle
  521. (
  522.     HWND            hwnd,
  523.     PCTSTR          pszFileTitle
  524. )
  525. {
  526.     static  TCHAR   szFormatTitle[]     = TEXT("%s - %s");
  527.     TCHAR       ach[APP_MAX_FILE_PATH_CHARS];
  528.     //
  529.     //  format the title text as 'AppName - FileTitle'
  530.     //
  531.     wsprintf(ach, szFormatTitle, (LPSTR)gszAppName, (LPSTR)pszFileTitle);
  532.     SetWindowText(hwnd, ach);
  533.     return (TRUE);
  534. } // AppTitle()
  535. //--------------------------------------------------------------------------;
  536. //
  537. //  BOOL AppFileNew
  538. //
  539. //  Description:
  540. //      This function is called to handle the IDM_FILE_NEW message. It is
  541. //      responsible for clearing the working area for a new unnamed file.
  542. //
  543. //  Arguments:
  544. //      HWND hwnd: Handle to application window.
  545. //
  546. //      PTSTR pszFilePath: Pointer to current null terminated file path.
  547. //      This buffer will be reinitialized if the function succeeds.
  548. //
  549. //      PTSTR pszFileTitle: Pointer to current null terminated file title.
  550. //      This buffer will be reinitialized if the function succeeds.
  551. //
  552. //  Return (BOOL):
  553. //      The return value is TRUE if the working area was cleared and is
  554. //      ready for new stuff. The return value is FALSE if the user canceled
  555. //      the operation.
  556. //
  557. //  History:
  558. //       2/ 6/93    created.
  559. //
  560. //--------------------------------------------------------------------------;
  561. BOOL FNGLOBAL AppFileNew
  562. (
  563.     HWND            hwnd,
  564.     PTSTR           pszFilePath,
  565.     PTSTR           pszFileTitle
  566. )
  567. {
  568.     BOOL    f;
  569.     //
  570.     //  if there is currently a file path, then we have to do some real
  571.     //  work...
  572.     //
  573.     if ('' != pszFilePath[0])
  574.     {
  575.         f = MciAppFileNew(hwnd, pszFilePath, pszFileTitle);
  576.         if (!f)
  577.             return (FALSE);
  578.     }
  579.     //
  580.     //  blow away the old file path and title; set the window title and
  581.     //  return success
  582.     //
  583.     lstrcpy(pszFilePath,  gszFileUntitled);
  584.     lstrcpy(pszFileTitle, gszFileUntitled);
  585.     AppTitle(hwnd, pszFileTitle);
  586.     MciAppResetStatus(hwnd);
  587.     AppSetWindowTextId(GetDlgItem(hwnd, IDD_APP_TEXT_STATUS),
  588.                        IDS_MCI_SCRIPT_CREATED, (LPSTR)pszFilePath);
  589.     SetFocus(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT));
  590.     return (TRUE);
  591. } // AppFileNew()
  592. //--------------------------------------------------------------------------;
  593. //
  594. //  BOOL AppFileOpen
  595. //
  596. //  Description:
  597. //      This function handles the IDM_FILE_OPEN message. It is responsible
  598. //      for getting a new file name from the user and opening that file
  599. //      if possible.
  600. //
  601. //  Arguments:
  602. //      HWND hwnd: Handle to application window.
  603. //
  604. //      PTSTR pszFilePath: Pointer to current null terminated file path.
  605. //      This buffer will contain the new file path if one is selected.
  606. //
  607. //      PTSTR pszFileTitle: Pointer to current null terminated file title.
  608. //      This buffer will contain the new file title if one is selected.
  609. //
  610. //  Return (BOOL):
  611. //      The return value is TRUE if a new file was selected and opened.
  612. //      It is FALSE if the user canceled the operation.
  613. //
  614. //  History:
  615. //       2/ 6/93    created.
  616. //
  617. //--------------------------------------------------------------------------;
  618. BOOL FNLOCAL AppFileOpen
  619. (
  620.     HWND            hwnd,
  621.     PTSTR           pszFilePath,
  622.     PTSTR           pszFileTitle
  623. )
  624. {
  625.     TCHAR       szFilePath[APP_MAX_FILE_PATH_CHARS];
  626.     TCHAR       szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  627.     BOOL        f;
  628.     //
  629.     //  first test for a modified script that has not been saved. if the
  630.     //  return value is FALSE we should cancel the File.Open operation.
  631.     //
  632.     f = MciAppFileSaveModified(hwnd, pszFilePath, pszFileTitle);
  633.     if (!f)
  634.         return (FALSE);
  635.     //
  636.     //  get the file name of the new script into temporary buffers (so
  637.     //  if we fail to open it we can back out cleanly).
  638.     //
  639.     f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GFNF_OPEN);
  640.     if (!f)
  641.         return (FALSE);
  642.     //
  643.     //  read the new script...
  644.     //
  645.     f = MciAppFileOpen(hwnd, szFilePath, NULL);
  646.     if (f)
  647.     {
  648.         //
  649.         //  copy the new file path and title into the global buffers and
  650.         //  set the window title text...
  651.         //
  652.         lstrcpy(gszAppFilePath,  szFilePath);
  653.         lstrcpy(gszAppFileTitle, szFileTitle);
  654.         AppTitle(hwnd, szFileTitle);
  655.         MciAppResetStatus(hwnd);
  656.         AppSetWindowTextId(GetDlgItem(hwnd, IDD_APP_TEXT_STATUS),
  657.                            IDS_MCI_SCRIPT_OPENED, (LPSTR)szFilePath);
  658.         SetFocus(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT));
  659.     }
  660.     return (f);
  661. } // AppFileOpen()
  662. //--------------------------------------------------------------------------;
  663. //
  664. //  BOOL AppFileSave
  665. //
  666. //  Description:
  667. //      This function handles the IDM_FILE_SAVE[AS] messages. It is
  668. //      responsible for saving the current file. If a file name needs
  669. //      to be specified then the save file dialog is displayed.
  670. //
  671. //  Arguments:
  672. //      HWND hwnd: Handle to application window.
  673. //
  674. //      PTSTR pszFilePath: Pointer to current null terminated file path.
  675. //      This buffer will contain the new file path if one is selected.
  676. //
  677. //      PTSTR pszFileTitle: Pointer to current null terminated file title.
  678. //      This buffer will contain the new file title if one is selected.
  679. //
  680. //      BOOL fSaveAs: TRUE if the save file chooser should be displayed
  681. //      before saving the file. FALSE if should operate like File.Save.
  682. //
  683. //  Return (BOOL):
  684. //      The return value is TRUE if the file was saved. It is FALSE if the
  685. //      user canceled the operation or the file does not need saved.
  686. //
  687. //  History:
  688. //       2/ 6/93    created.
  689. //
  690. //--------------------------------------------------------------------------;
  691. BOOL FNGLOBAL AppFileSave
  692. (
  693.     HWND            hwnd,
  694.     PTSTR           pszFilePath,
  695.     PTSTR           pszFileTitle,
  696.     BOOL            fSaveAs
  697. )
  698. {
  699.     TCHAR       szFilePath[APP_MAX_FILE_PATH_CHARS];
  700.     TCHAR       szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  701.     BOOL        f;
  702.     //
  703.     //  check if we should bring up the save file chooser dialog...
  704.     //
  705.     if (fSaveAs || !lstrcmp(pszFileTitle, gszFileUntitled))
  706.     {
  707.         //
  708.         //  get the file name for saving the script to into temporary
  709.         //  buffers (so if we fail to save it we can back out cleanly).
  710.         //
  711.         f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GFNF_SAVE);
  712.         if (!f)
  713.             return (FALSE);
  714.     }
  715.     else
  716.     {
  717.         //
  718.         //  copy the file path into our temporary buffer so we don't have
  719.         //  to special case this on MciAppFileSave..
  720.         //
  721.         lstrcpy(szFilePath,  pszFilePath);
  722.         lstrcpy(szFileTitle, pszFileTitle);
  723.     }
  724.     //
  725.     //  save the script...
  726.     //
  727.     f = MciAppFileSave(hwnd, szFilePath);
  728.     if (f)
  729.     {
  730.         //
  731.         //  copy the (possibly) new file path and title into the global
  732.         //  buffers and set the window title text...
  733.         //
  734.         lstrcpy(gszAppFilePath,  szFilePath);
  735.         lstrcpy(gszAppFileTitle, szFileTitle);
  736.         AppTitle(hwnd, szFileTitle);
  737.         //
  738.         //  changes have been saved, so clear the modified bit...
  739.         //
  740.         Edit_SetModify(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT), FALSE);
  741.         AppSetWindowTextId(GetDlgItem(hwnd, IDD_APP_TEXT_STATUS),
  742.                            IDS_MCI_SCRIPT_SAVED, (LPSTR)szFilePath);
  743.         SetFocus(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT));
  744.     }
  745.     return (f);
  746. } // AppFileSave()
  747. //==========================================================================;
  748. //
  749. //  Main application window handling code...
  750. //
  751. //
  752. //==========================================================================;
  753. //--------------------------------------------------------------------------;
  754. //
  755. //  LRESULT AppInitMenuPopup
  756. //
  757. //  Description:
  758. //      This function handles the WM_INITMENUPOPUP message. This message
  759. //      is sent to the window owning the menu that is going to become
  760. //      active. This gives an application the ability to modify the menu
  761. //      before it is displayed (disable/add items, etc).
  762. //
  763. //  Arguments:
  764. //      HWND hwnd: Handle to window that generated the WM_INITMENUPOPUP
  765. //      message.
  766. //
  767. //      HMENU hmenu: Handle to the menu that is to become active.
  768. //
  769. //      int nItem: Specifies the zero-based relative position of the menu
  770. //      item that invoked the popup menu.
  771. //
  772. //      BOOL fSysMenu: Specifies whether the popup menu is a System menu
  773. //      (TRUE) or it is not a System menu (FALSE).
  774. //
  775. //  Return (LRESULT):
  776. //      Returns zero if the message is processed.
  777. //
  778. //  History:
  779. //       1/ 2/93    created.
  780. //
  781. //--------------------------------------------------------------------------;
  782. LRESULT FNLOCAL AppInitMenuPopup
  783. (
  784.     HWND            hwnd,
  785.     HMENU           hmenu,
  786.     int             nItem,
  787.     BOOL            fSysMenu
  788. )
  789. {
  790.     BOOL    f;
  791.     int     nSelStart;
  792.     int     nSelEnd;
  793.     HWND    hwndScript;
  794.     DPF(0, "AppInitMenuPopup(hwnd=%Xh, hmenu=%Xh, nItem=%d, fSysMenu=%d)",
  795.             hwnd, hmenu, nItem, fSysMenu);
  796.     //
  797.     //  if the system menu is what got hit, succeed immediately... this
  798.     //  application has no stuff in the system menu.
  799.     //
  800.     if (fSysMenu)
  801.         return (0L);
  802.     //
  803.     //  initialize the menu that is being 'popped up'
  804.     //
  805.     switch (nItem)
  806.     {
  807.         case APP_MENU_ITEM_FILE:
  808.             //
  809.             //  if the script has been modified, then enable the File.Save
  810.             //  menu
  811.             //
  812.             hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  813.             f = Edit_GetModify(hwndScript);
  814.             EnableMenuItem(hmenu, IDM_FILE_SAVE,
  815.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  816.             break;
  817.         case APP_MENU_ITEM_EDIT:
  818.             //
  819.             //  check to see if something is selected in the script edit
  820.             //  window and enable/disable Edit menu options appropriately
  821.             //
  822.             hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  823.             Edit_GetSelEx(hwndScript, &nSelStart, &nSelEnd);
  824.             f = (nSelStart != nSelEnd);
  825.             EnableMenuItem(hmenu, WM_CUT,   (UINT)(f ? MF_ENABLED : MF_GRAYED));
  826.             EnableMenuItem(hmenu, WM_COPY,  (UINT)(f ? MF_ENABLED : MF_GRAYED));
  827.             EnableMenuItem(hmenu, WM_CLEAR, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  828.             f = Edit_CanUndo(hwndScript);
  829.             EnableMenuItem(hmenu, WM_UNDO,  (UINT)(f ? MF_ENABLED : MF_GRAYED));
  830.             f = IsClipboardFormatAvailable(CF_TEXT);
  831.             EnableMenuItem(hmenu, WM_PASTE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  832.             break;
  833.         case APP_MENU_ITEM_DEVICE:
  834.             //
  835.             //
  836.             //
  837.             f = (0 != (gfuAppOptions & APP_OPTF_DEVICELIST));
  838.             CheckMenuItem(hmenu, IDM_DEVICE_OPENLIST,
  839.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  840.             f = (MciAppGetNumDevices(hwnd) != 0);
  841.             EnableMenuItem(hmenu, IDM_DEVICE_CLOSEALL,
  842.                            (UINT)(f ? MF_ENABLED : MF_GRAYED));
  843.             break;
  844.         case APP_MENU_ITEM_OPTIONS:
  845.             //
  846.             //  make sure the options that need a checkmark are checked..
  847.             //
  848.             f = (0 != (gfuAppOptions & APP_OPTF_EDITONLY));
  849.             CheckMenuItem(hmenu, IDM_OPTIONS_EDITONLY,
  850.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  851.             f = (0 != (gfuAppOptions & APP_OPTF_YIELDEXEC));
  852.             CheckMenuItem(hmenu, IDM_OPTIONS_YIELDEXEC,
  853.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  854.             f = (0 != (gfuAppOptions & APP_OPTF_DEBUGLOG));
  855.             CheckMenuItem(hmenu, IDM_OPTIONS_DEBUGLOG,
  856.                           (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  857.             break;
  858.     }
  859.     //
  860.     //  we processed the message--return 0...
  861.     //
  862.     return (0L);
  863. } // AppInitMenuPopup()
  864. //--------------------------------------------------------------------------;
  865. //
  866. //  LRESULT AppCommand
  867. //
  868. //  Description:
  869. //      This function handles the WM_COMMAND message.
  870. //
  871. //  Arguments:
  872. //      HWND hwnd: Handle to window receiving the WM_COMMAND message.
  873. //
  874. //      int nId: Control or menu item identifier.
  875. //
  876. //      HWND hwndCtl: Handle of control if the message is from a control.
  877. //      This argument is NULL if the message was not generated by a control.
  878. //
  879. //      UINT uCode: Notification code. This argument is 1 if the message
  880. //      was generated by an accelerator. If the message is from a menu,
  881. //      this argument is 0.
  882. //
  883. //  Return (LRESULT):
  884. //      Returns zero if the message is processed.
  885. //
  886. //  History:
  887. //      11/ 8/92    created.
  888. //
  889. //--------------------------------------------------------------------------;
  890. LRESULT FNLOCAL AppCommand
  891. (
  892.     HWND            hwnd,
  893.     int             nId,
  894.     HWND            hwndCtl,
  895.     UINT            uCode
  896. )
  897. {
  898.     BOOL        f;
  899.     if (gfExecuting)
  900.     {
  901.         if ((IDD_ACCL_ABORT == nId) || (IDD_APP_BTN_STOP == nId))
  902.             gfAbortExec = TRUE;
  903.         return (0L);
  904.     }
  905.     switch (nId)
  906.     {
  907.         case IDM_FILE_NEW:
  908.             AppFileNew(hwnd, gszAppFilePath, gszAppFileTitle);
  909.             break;
  910.         case IDM_FILE_OPEN:
  911.             AppFileOpen(hwnd, gszAppFilePath, gszAppFileTitle);
  912.             break;
  913.         case IDM_FILE_SAVE:
  914.             AppFileSave(hwnd, gszAppFilePath, gszAppFileTitle, FALSE);
  915.             break;
  916.         case IDM_FILE_SAVEAS:
  917.             AppFileSave(hwnd, gszAppFilePath, gszAppFileTitle, TRUE);
  918.             break;
  919.         case IDM_FILE_ABOUT:
  920.             DialogBox(ghinst, DLG_ABOUT, hwnd, (DLGPROC)AboutDlgProc);
  921.             break;
  922.         case IDM_FILE_EXIT:
  923.             FORWARD_WM_CLOSE(hwnd, SendMessage);
  924.             break;
  925.         case WM_UNDO:
  926.         case WM_CUT:
  927.         case WM_COPY:
  928.         case WM_PASTE:
  929.         case WM_CLEAR:
  930.             //
  931.             //  pass edit messages received to the script edit window
  932.             //
  933.             SendMessage(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT), nId, 0, 0L);
  934.             break;
  935.         case IDM_EDIT_SELECTALL:
  936.             Edit_SetSel(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT), 0, -1);
  937.             break;
  938.         case IDM_DEVICE_CLOSEALL:
  939.             MciAppCloseAllDevices(hwnd);
  940.             break;
  941.         case IDM_OPTIONS_EDITONLY:
  942.             gfuAppOptions ^= APP_OPTF_EDITONLY;
  943.             MciAppUpdateOptions(hwnd);
  944.             break;
  945.         case IDM_OPTIONS_YIELDEXEC:
  946.             gfuAppOptions ^= APP_OPTF_YIELDEXEC;
  947.             MciAppUpdateOptions(hwnd);
  948.             break;
  949.         case IDM_OPTIONS_DEBUGLOG:
  950.             gfuAppOptions ^= APP_OPTF_DEBUGLOG;
  951.             MciAppUpdateOptions(hwnd);
  952.             break;
  953.         case IDM_DEVICE_OPENLIST:
  954.             //
  955.             //  bring up the device list dialog--if this event was triggered
  956.             //  by an accelerator (uCode == 1) then do not give the focus
  957.             //  to the dialog. if this event was triggered by the user
  958.             //  selecting the menu option with the mouse, then give the
  959.             //  focus to the device list dialog...
  960.             //
  961.             gfuAppOptions ^= APP_OPTF_DEVICELIST;
  962.             MciAppDeviceList(hwnd, (1 != uCode));
  963.             break;
  964.         case IDM_OPTIONS_FONT:
  965.             MciAppChooseFont(hwnd);
  966.             break;
  967.         case IDD_APP_BTN_STEP:
  968.             //
  969.             //  execute the current line in the script window
  970.             //
  971.             MciAppSingleStep(hwnd);
  972.             break;
  973.         case IDD_APP_BTN_RUN:
  974.             //
  975.             //  execute every line in the script window starting from the
  976.             //  _first_ line..
  977.             //
  978.             Edit_SetSel(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT), 0, 0);
  979.             // -- Fall Through --
  980.         case IDD_APP_BTN_GO:
  981.             //
  982.             //  execute every line in the script window starting from the
  983.             //  _current_ line..
  984.             //
  985.             f = (0 != (gfuAppOptions & APP_OPTF_YIELDEXEC));
  986.             MciAppExecute(hwnd, f);
  987.             break;
  988.         case IDOK:
  989.             //
  990.             //  when we receive an IDOK for the script window (user pressed
  991.             //  return key), 'enter' the new line...
  992.             //
  993.             //  uCode will be 0 if Alt+Enter was pressed, so reverse the
  994.             //  logic of the Edit Only option in this case
  995.             //
  996.             if (GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT) == hwndCtl)
  997.             {
  998.                 f = (0 != (gfuAppOptions & APP_OPTF_EDITONLY));
  999.                 MciAppEnterLine(hwnd, (1 == uCode) ? f : !f);
  1000.             }
  1001.             break;
  1002.     }
  1003.     return (0L);
  1004. } // AppCommand()
  1005. //--------------------------------------------------------------------------;
  1006. //
  1007. //  LRESULT AppDropFiles
  1008. //
  1009. //  Description:
  1010. //      This function handles the WM_DROPFILES message. This message is
  1011. //      sent when files are 'dropped' on the window from file manager
  1012. //      (or other drag/drop servers made by ISV's that figured out the
  1013. //      undocumented internal workings of the SHELL).
  1014. //
  1015. //      A window must be registered to receive these messages either by
  1016. //      called DragAcceptFiles() or using CreateWindowEx() with the
  1017. //      WS_EX_ACCEPTFILES style bit.
  1018. //
  1019. //  Arguments:
  1020. //      HWND hwnd: Handle to window receiving the message.
  1021. //
  1022. //      HDROP hdrop: Handle to drop structure.
  1023. //
  1024. //  Return (LRESULT):
  1025. //      Returns 0 if the message is processed.
  1026. //
  1027. //  History:
  1028. //       2/ 8/93    created.
  1029. //
  1030. //--------------------------------------------------------------------------;
  1031. LRESULT FNLOCAL AppDropFiles
  1032. (
  1033.     HWND            hwnd,
  1034.     HDROP           hdrop
  1035. )
  1036. {
  1037.     TCHAR       szFileTitle[APP_MAX_FILE_PATH_CHARS];
  1038.     TCHAR       szFilePath[APP_MAX_FILE_PATH_CHARS];
  1039.     UINT        uNumFiles;
  1040.     UINT        u;
  1041.     BOOL        f;
  1042.     int         n;
  1043.     //
  1044.     //  if executing a script and this message is received, we bail...
  1045.     //  too much code to fix this...
  1046.     //
  1047.     if (gfExecuting)
  1048.     {
  1049.         MessageBeep((UINT)-1);
  1050.         goto App_Drop_Files_Exit;
  1051.     }
  1052.     //
  1053.     //  first test for a modified script that has not been saved. if the
  1054.     //  return value is FALSE we should cancel the drop operation.
  1055.     //
  1056.     f = MciAppFileSaveModified(hwnd, gszAppFilePath, gszAppFileTitle);
  1057.     if (!f)
  1058.         goto App_Drop_Files_Exit;
  1059.     //
  1060.     //  get number of files dropped on our window
  1061.     //
  1062.     uNumFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
  1063.     DPF(0, "AppDropFiles(hwnd=%Xh, hdrop=%Xh)--uNumFiles=%u",
  1064.              hwnd, hdrop, uNumFiles);
  1065.     //
  1066.     //  step through each file and stop on the one the user wants or
  1067.     //  the last file (whichever comes first).
  1068.     //
  1069.     for (u = 0; u < uNumFiles; u++)
  1070.     {
  1071.         //
  1072.         //  get the next file name and try to open it--if not a valid
  1073.         //  file, then skip to the next one (if there is one).
  1074.         //
  1075.         DragQueryFile(hdrop, u, szFilePath, SIZEOF(szFilePath));
  1076.         //
  1077.         //  attempt to open the file
  1078.         //
  1079.         f = MciAppFileOpen(hwnd, szFilePath, szFileTitle);
  1080.         if (!f)
  1081.             continue;
  1082.         //
  1083.         //  update display info
  1084.         //
  1085.         lstrcpy(gszAppFilePath, szFilePath);
  1086.         lstrcpy(gszAppFileTitle, szFileTitle);
  1087.         AppTitle(hwnd, szFileTitle);
  1088.         MciAppResetStatus(hwnd);
  1089.         AppSetWindowTextId(GetDlgItem(hwnd, IDD_APP_TEXT_STATUS),
  1090.                            IDS_MCI_SCRIPT_OPENED, (LPSTR)szFilePath);
  1091.         //
  1092.         //  if this is NOT the last file in the list of files that are
  1093.         //  being dropped on us, then bring up a box asking if we should
  1094.         //  continue or stop where we are..
  1095.         //
  1096.         if ((uNumFiles - 1) != u)
  1097.         {
  1098.             n = AppMsgBoxId(hwnd, MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL,
  1099.                             IDS_DROP_CONTINUE);
  1100.             if (IDNO == n)
  1101.                 break;
  1102.         }
  1103.     }
  1104.     //
  1105.     //  tell the shell to release the memory it allocated for beaming
  1106.     //  the file name(s) over to us... return 0 to show we processed
  1107.     //  the message.
  1108.     //
  1109. App_Drop_Files_Exit:
  1110.     DragFinish(hdrop);
  1111.     return (0L);
  1112. } // AppDropFiles()
  1113. //--------------------------------------------------------------------------;
  1114. //
  1115. //  LRESULT AppSize
  1116. //
  1117. //  Description:
  1118. //      This function handles the WM_SIZE message for the application's
  1119. //      window. This message is sent to the application window after the
  1120. //      size has changed (but before it is painted).
  1121. //
  1122. //  Arguments:
  1123. //      HWND hwnd: Handle to window that generated the WM_SIZE message.
  1124. //
  1125. //      UINT fuSizeType: Specifies the type of resizing requested. This
  1126. //      argument is one of the following: SIZE_MAXIMIZED, SIZE_MINIMIZED,
  1127. //      SIZE_RESTORED, SIZE_MAXHIDE, or SIZE_MAXSHOW.
  1128. //
  1129. //      int nWidth: Width of the new client area for the window.
  1130. //
  1131. //      int nHeight: Height of the new client area for the window.
  1132. //
  1133. //  Return (LRESULT):
  1134. //      Returns zero if the application processes the message.
  1135. //
  1136. //  History:
  1137. //       2/ 5/93    created.
  1138. //
  1139. //--------------------------------------------------------------------------;
  1140. LRESULT FNLOCAL AppSize
  1141. (
  1142.     HWND            hwnd,
  1143.     UINT            fuSizeType,
  1144.     int             nWidth,
  1145.     int             nHeight
  1146. )
  1147. {
  1148.     HWND    hwndButton;
  1149.     HWND    hwndOutput;
  1150.     HWND    hwndScript;
  1151.     HWND    hwndStatus;
  1152.     HWND    hwndSeparator;
  1153.     HWND    hwndNotify;
  1154.     HWND    hwndOptions;
  1155.     RECT    rc;
  1156.     int     nHeightButton;
  1157.     int     nWidthButton;
  1158.     int     nHeightScript;
  1159.     int     nHeightStatus;
  1160.     int     n, m;
  1161.     int     nWidthNotify;
  1162.     DPF(0, "AppSize(hwnd=%Xh, fuSizeType=%u, nWidth=%d, nHeight=%d)",
  1163.             hwnd, fuSizeType, nWidth, nHeight);
  1164.     //
  1165.     //  unless this application is the one being resized then don't waste
  1166.     //  time computing stuff that doesn't matter. this applies to being
  1167.     //  minimized also because this application does not have a custom
  1168.     //  minimized state.
  1169.     //
  1170.     if ((SIZE_RESTORED != fuSizeType) && (SIZE_MAXIMIZED != fuSizeType))
  1171.         return (0L);
  1172.     //
  1173.     //  for this application, we have three different sections that need
  1174.     //  to be fit into the newly sized client area--it looks roughly like
  1175.     //  this:
  1176.     //
  1177.     //  +-------------------------------------------+
  1178.     //  | - |        MCI App - ZYZSMAG.MCI      |^|v| <- title bar
  1179.     //  +-------------------------------------------+
  1180.     //  | File Edit Options                         | <- menu bar
  1181.     //  +-------------------------------------------+
  1182.     //  |{Step}{ Go }{ Run } Count:[x ] Output: zyz | <- button bar
  1183.     //  +-------------------------------------------+
  1184.     //  | MCI script window                         | <- script window
  1185.     //  |                                           |
  1186.     //  |                                           |
  1187.     //  |                                           |
  1188.     //  |                                           |
  1189.     //  |                                           |
  1190.     //  |                                           |
  1191.     //  +-------------------------------------------+
  1192.     //  | Silly status bar      | Notify: zyz | EYL | <- options status
  1193.     //  +-------------------------------------------+
  1194.     //       ^                  ^   ^
  1195.     //       +- status bar      |   +- notify window
  1196.     //                          |
  1197.     //                          +----- separator
  1198.     //
  1199.     //  the 'button bar' does not have to move or change size (except the
  1200.     //  width of the output window)
  1201.     //
  1202.     //  the 'script window' should fill all space between the bottom of
  1203.     //  the button bar and the top of the status bar.
  1204.     //
  1205.     //  the 'status bar' should sit on the bottom of the window and
  1206.     //  remain a constant height.
  1207.     //
  1208.     //  the 'notify window' should sit on the bottom of the window to the
  1209.     //  right of the status bar and remain a constant height.
  1210.     //
  1211.     //  the 'options status' window should sit in the bottom right corner
  1212.     //  and remain a constant width and height.
  1213.     //
  1214.     //  the 'separators' should be a visible separator between the status
  1215.     //  bar, notify window, and options status.
  1216.     //
  1217.     //
  1218.     //  first grab handles to all the windows we need to muck with...
  1219.     //
  1220.     hwndButton  = GetDlgItem(hwnd, IDD_APP_BTN_GO);
  1221.     hwndOutput  = GetDlgItem(hwnd, IDD_APP_TEXT_OUTPUT);
  1222.     hwndScript  = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  1223.     hwndStatus  = GetDlgItem(hwnd, IDD_APP_TEXT_STATUS);
  1224.     hwndNotify  = GetDlgItem(hwnd, IDD_APP_TEXT_NOTIFY);
  1225.     hwndOptions = GetDlgItem(hwnd, IDD_APP_TEXT_OPTIONS);
  1226.     //
  1227.     //  get the height of the button bar and status bar
  1228.     //
  1229.     GetClientRect(hwndButton, &rc);
  1230.     nHeightButton = (int)(rc.bottom - rc.top);
  1231.     nWidthButton  = (int)(rc.right - rc.left);
  1232.     //
  1233.     //  change width of output window..
  1234.     //
  1235.     GetClientRect(hwndStatus, &rc);
  1236.     nHeightStatus = (int)(rc.bottom - rc.top);
  1237.     n = nWidthButton * 6;
  1238.     m = (nWidth > (n + 2)) ? (nWidth - n - 2) : 0;
  1239.     rc.top = (nHeightButton - nHeightStatus) / 2;
  1240.     MoveWindow(hwndOutput, n, (int)rc.top, m, nHeightStatus, TRUE);
  1241.     //
  1242.     //  calculate the new height for the script window and move it to just
  1243.     //  below the bottom of the button bar and above the status bar (which
  1244.     //  is the height of the button bar)... note that we put the left and
  1245.     //  right edges of the script window outside of the client area because
  1246.     //  it looks better that way.
  1247.     //
  1248.     nHeightScript = nHeight - (nHeightButton * 2);
  1249.     if (nHeightScript < 0)
  1250.         nHeightScript = 0;
  1251.     MoveWindow(hwndScript, -1, nHeightButton, nWidth + 2, nHeightScript, TRUE);
  1252.     //
  1253.     //  put the status bar sitting on top of the bottom of the app window
  1254.     //  note that we center it in a space that is as high as the button
  1255.     //  bar so it looks better... it is assumed (correctly) that the button
  1256.     //  bar is taller than the status bar control.
  1257.     //
  1258.     //  ~                                           ~
  1259.     //  |                                           |
  1260.     //  +-------------------------------------------+
  1261.     //  | Silly status bar      | Notify: zyz | EYL |
  1262.     //  +-------------------------------------------+
  1263.     //  ^                       ^             ^     ^
  1264.     //  +------ min = 20 -------+-min = ~130 -+- 40-+
  1265.     //
  1266.     //  there is pad of 2 on the left and right of each text window (giving
  1267.     //  a separator a effective width of 5).
  1268.     //
  1269.     //
  1270.     nWidthNotify = (nWidth < (20 + 5 + 130 + 5 + 40)) ?
  1271.                         (nWidth - (20 + 5 + 5 + 40)) : 130;
  1272.     hwndSeparator = GetDlgItem(hwnd, IDD_APP_BOX_SEPARATOR1);
  1273.     MoveWindow(hwndSeparator, nWidth - nWidthNotify - 3 - 5 - 40,
  1274.                               nHeight - nHeightButton,
  1275.                               1, nHeightButton, TRUE);
  1276.     n = nHeightStatus + ((nHeightButton - nHeightStatus) / 2);
  1277.     MoveWindow(hwndStatus, 2, nHeight - n,
  1278.                            nWidth - nWidthNotify - 8 - 5 - 40,
  1279.                            nHeightStatus, TRUE);
  1280.     MoveWindow(hwndNotify, nWidth - nWidthNotify - 5 - 40, nHeight - n,
  1281.                            nWidthNotify - 2, nHeightStatus, TRUE);
  1282.     hwndSeparator = GetDlgItem(hwnd, IDD_APP_BOX_SEPARATOR2);
  1283.     MoveWindow(hwndSeparator, nWidth - 3 - 40,
  1284.                               nHeight - nHeightButton,
  1285.                               1, nHeightButton, TRUE);
  1286.     MoveWindow(hwndOptions, nWidth - 40, nHeight - n,
  1287.                            40 - 2, nHeightStatus, TRUE);
  1288.     //
  1289.     //  we processed the message..
  1290.     //
  1291.     return (0L);
  1292. } // AppSize()
  1293. //--------------------------------------------------------------------------;
  1294. //
  1295. //  LRESULT AppWndProc
  1296. //
  1297. //  Description:
  1298. //      This is the main application window procedure.
  1299. //
  1300. //  Arguments:
  1301. //      HWND hwnd: Handle to window.
  1302. //
  1303. //      UINT uMsg: Message being sent to the window.
  1304. //
  1305. //      WPARAM wParam: Specific argument to message.
  1306. //
  1307. //      LPARAM lParam: Specific argument to message.
  1308. //
  1309. //  Return (LRESULT):
  1310. //      The return value depends on the message that is being processed.
  1311. //
  1312. //  History:
  1313. //      11/ 8/92    created.
  1314. //
  1315. //--------------------------------------------------------------------------;
  1316. LRESULT FNEXPORT AppWndProc
  1317. (
  1318.     HWND            hwnd,
  1319.     UINT            uMsg,
  1320.     WPARAM          wParam,
  1321.     LPARAM          lParam
  1322. )
  1323. {
  1324.     LRESULT     lr;
  1325.     switch (uMsg)
  1326.     {
  1327.         case WM_CREATE:
  1328.             lr = HANDLE_WM_CREATE(hwnd, wParam, lParam, AppCreate);
  1329.             return (lr);
  1330.         case WM_WININICHANGE:
  1331.             HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, AppWinIniChange);
  1332.             return (0L);
  1333.         case WM_INITMENUPOPUP:
  1334.             HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, AppInitMenuPopup);
  1335.             return (0L);
  1336.         case WM_COMMAND:
  1337.             lr = HANDLE_WM_COMMAND(hwnd, wParam, lParam, AppCommand);
  1338.             return (lr);
  1339.         case WM_DROPFILES:
  1340.             //
  1341.             //  some windowsx.h files have a screwed up message cracker for
  1342.             //  WM_DROPFILES. because this is a sample app, i don't want
  1343.             //  people having trouble with bogus windowsx.h files, so crack
  1344.             //  the message manually... you should use the message cracker
  1345.             //  if you know your windowsx.h file is good.
  1346.             //
  1347.             //  lr = HANDLE_WM_DROPFILES(hwnd, wParam, lParam, AppDropFiles);
  1348.             //
  1349.             lr = AppDropFiles(hwnd, (HDROP)wParam);
  1350.             return (lr);
  1351.         case WM_SIZE:
  1352.             //
  1353.             //  handle what we want for sizing, and then always call the
  1354.             //  default handler...
  1355.             //
  1356.             HANDLE_WM_SIZE(hwnd, wParam, lParam, AppSize);
  1357.             break;
  1358.         case WM_QUERYENDSESSION:
  1359.             lr = HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, AppQueryEndSession);
  1360.             return (lr);
  1361.         case WM_ENDSESSION:
  1362.             HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, AppEndSession);
  1363.             return (0L);
  1364.         case WM_CLOSE:
  1365.             HANDLE_WM_CLOSE(hwnd, wParam, lParam, AppClose);
  1366.             return (0L);
  1367.         case WM_DESTROY:
  1368.             PostQuitMessage(0);
  1369.             return (0L);
  1370.         case MM_MCINOTIFY:
  1371.             MciAppHandleNotify(hwnd, wParam, LOWORD(lParam));
  1372.             break;
  1373.     }
  1374.     return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1375. } // AppWndProc()
  1376. //==========================================================================;
  1377. //
  1378. //  Main entry and message dispatching code
  1379. //
  1380. //
  1381. //==========================================================================;
  1382. //--------------------------------------------------------------------------;
  1383. //
  1384. //  int WinMain
  1385. //
  1386. //  Description:
  1387. //      This function is called by the system as the initial entry point
  1388. //      for a Windows application.
  1389. //
  1390. //  Arguments:
  1391. //      HINSTANCE hinst: Identifies the current instance of the
  1392. //      application.
  1393. //
  1394. //      HINSTANCE hinstPrev: Identifies the previous instance of the
  1395. //      application (NULL if first instance). For Win 32, this argument
  1396. //      is _always_ NULL.
  1397. //
  1398. //      LPSTR pszCmdLine: Points to null-terminated unparsed command line.
  1399. //      This string is strictly ANSI regardless of whether the application
  1400. //      is built for Unicode. To get the Unicode equivalent call the
  1401. //      GetCommandLine() function (Win 32 only).
  1402. //
  1403. //      int nCmdShow: How the main window for the application is to be
  1404. //      shown by default.
  1405. //
  1406. //  Return (int):
  1407. //      Returns result from WM_QUIT message (in wParam of MSG structure) if
  1408. //      the application is able to enter its message loop. Returns 0 if
  1409. //      the application is not able to enter its message loop.
  1410. //
  1411. //  History:
  1412. //      11/ 8/92    created.
  1413. //
  1414. //--------------------------------------------------------------------------;
  1415. int PASCAL WinMain
  1416. (
  1417.     HINSTANCE       hinst,
  1418.     HINSTANCE       hinstPrev,
  1419.     LPSTR           pszCmdLine,
  1420.     int             nCmdShow
  1421. )
  1422. {
  1423.     int     nResult;
  1424.     HWND    hwnd;
  1425.     MSG     msg;
  1426.     //
  1427.     //  our documentation states that WinMain is supposed to return 0 if
  1428.     //  we do not enter our message loop--so assume the worst...
  1429.     //
  1430.     nResult = 0;
  1431.     //
  1432.     //  make our instance handle global for convenience..
  1433.     //
  1434.     ghinst = hinst;
  1435.     //
  1436.     //  init some stuff, create window, etc.. note the explicit cast of
  1437.     //  pszCmdLine--this is to mute a warning (and an ugly ifdef) when
  1438.     //  compiling for Unicode. see AppInit() for more details.
  1439.     //
  1440.     hwnd = AppInit(hinst, hinstPrev, (LPTSTR)pszCmdLine, nCmdShow);
  1441.     if (hwnd)
  1442.     {
  1443.         //
  1444.         //  dispatch messages
  1445.         //
  1446.         while (GetMessage(&msg, NULL, 0, 0))
  1447.         {
  1448.             //
  1449.             //  do all the special stuff required for this application
  1450.             //  when dispatching messages..
  1451.             //
  1452.             MciAppDispatchMessage(hwnd, &msg);
  1453.         }
  1454.         //
  1455.         //  return result of WM_QUIT message.
  1456.         //
  1457.         nResult = (int)msg.wParam;
  1458.     }
  1459.     //
  1460.     //  shut things down, clean up, etc.
  1461.     //
  1462.     nResult = AppExit(hinst, nResult);
  1463.     return (nResult);
  1464. } // WinMain()