home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / audio / mciapp / mciapp.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  72KB  |  2,587 lines

  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. //  mciapp.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. //       2/ 6/93    created.
  21. //
  22. //==========================================================================;
  23.  
  24. #include <windows.h>
  25. #include <windowsx.h>
  26. #include <mmsystem.h>
  27. #include <commdlg.h>
  28. #include <stdarg.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include "appport.h"
  32. #include "app.h"
  33. #include "mciapp.h"
  34.  
  35. #include "debug.h"
  36.  
  37.  
  38. //
  39. //
  40. //
  41. BOOL            gfExecuting;
  42. BOOL            gfAbortExec;
  43.  
  44.  
  45. HWND            ghwndDevices;
  46.  
  47. TCHAR           gszNone[]           = TEXT("(none)");
  48.  
  49.  
  50. //--------------------------------------------------------------------------;
  51. //
  52. //  BOOL MciAppFileSaveModified
  53. //
  54. //  Description:
  55. //      This function tests if the current script has been modified, and
  56. //      if it has it gives the option of saving the file.
  57. //
  58. //      NOTE! This function does *NOT* clear the modified bit for the
  59. //      script window. The calling function must do this if necessary.
  60. //
  61. //  Arguments:
  62. //      HWND hwnd: Handle to main window.
  63. //
  64. //      PTSTR pszFilePath: Pointer to null terminated file path of current
  65. //      script. This buffer will receive the new file path if one is chosen.
  66. //
  67. //      PTSTR pszFileTitle: Pointer to null terminated file title of
  68. //      current script. This buffer will receive the new file title if one
  69. //      is chosen.
  70. //
  71. //  Return (BOOL):
  72. //      Returns TRUE if the calling function should continue--the file was
  73. //      either saved or the user does not wish to save it. Returns FALSE
  74. //      if the calling function should cancel its operation--the user
  75. //      wants to keep the data, but it has not been saved.
  76. //
  77. //  History:
  78. //       2/ 6/93    created.
  79. //
  80. //--------------------------------------------------------------------------;
  81.  
  82. BOOL FNGLOBAL MciAppFileSaveModified
  83. (
  84.     HWND            hwnd,
  85.     PTSTR           pszFilePath,
  86.     PTSTR           pszFileTitle
  87. )
  88. {
  89.     BOOL    f;
  90.     int     n;
  91.     HWND    hwndScript;
  92.  
  93.     //
  94.     //  check if the contents of the script window have been modified--if
  95.     //  they have then ask the user if they want to save the current
  96.     //  contents...
  97.     //
  98.     hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  99.     f = Edit_GetModify(hwndScript);
  100.     if (f)
  101.     {
  102.         //
  103.         //  display an appropriate message box asking for the user's opinion
  104.         //
  105.         n = AppMsgBoxId(hwnd, MB_YESNOCANCEL | MB_ICONQUESTION| MB_SETFOREGROUND,
  106.                         IDS_MCI_SCRIPT_CHANGED, (LPSTR)pszFilePath);
  107.         switch (n)
  108.         {
  109.             case IDYES:
  110.                 f = AppFileSave(hwnd, pszFilePath, pszFileTitle, FALSE);
  111.                 if (f)
  112.                     break;
  113.  
  114.                 // -- fall through --
  115.  
  116.             case IDCANCEL:
  117.                 //
  118.                 //  don't continue!
  119.                 //
  120.                 return (FALSE);
  121.  
  122.             case IDNO:
  123.                 break;
  124.         }
  125.     }
  126.  
  127.     //
  128.     //  ok to continue...
  129.     //
  130.     return (TRUE);
  131. } // MciAppFileSaveModified()
  132.  
  133.  
  134. //--------------------------------------------------------------------------;
  135. //
  136. //  BOOL MciAppFileNew
  137. //
  138. //  Description:
  139. //      This function simply clears the script window. If a modified script
  140. //      will be destroyed, then the user is asked if the script should be
  141. //      saved first.
  142. //
  143. //  Arguments:
  144. //      HWND hwnd: Handle to main window.
  145. //
  146. //      PTSTR pszFilePath: Pointer to null terminated file path of current
  147. //      script. This buffer will receive the newly initialized file path.
  148. //
  149. //      PTSTR pszFileTitle: Pointer to null terminated file title of
  150. //      current script. This buffer will receive the newly initialized file
  151. //      title.
  152. //
  153. //  Return (BOOL):
  154. //      The return value is TRUE if the script window was cleared. It is
  155. //      FALSE if the user canceled the operation.
  156. //
  157. //  History:
  158. //       2/ 6/93    created.
  159. //
  160. //--------------------------------------------------------------------------;
  161.  
  162. BOOL FNGLOBAL MciAppFileNew
  163. (
  164.     HWND            hwnd,
  165.     PTSTR           pszFilePath,
  166.     PTSTR           pszFileTitle
  167. )
  168. {
  169.     BOOL    f;
  170.     HWND    hwndScript;
  171.  
  172.     //
  173.     //  test for a modified script first...
  174.     //
  175.     f = MciAppFileSaveModified(hwnd, pszFilePath, pszFileTitle);
  176.     if (!f)
  177.         return (FALSE);
  178.  
  179.     //
  180.     //  blow away all the text and set the modified bit to 'NOT'
  181.     //
  182.     hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  183.     SetWindowText(hwndScript, gszNull);
  184.     Edit_SetModify(hwndScript, FALSE);
  185.  
  186.     //
  187.     //  success
  188.     //
  189.     return (TRUE);
  190. } // MciAppFileNew()
  191.  
  192.  
  193. //--------------------------------------------------------------------------;
  194. //
  195. //  BOOL MciAppFileOpen
  196. //
  197. //  Description:
  198. //      This function opens the specified text file and copies the contents
  199. //      of the file into the script edit control.
  200. //
  201. //      NOTE! This function does NOT check for a modified script! It is
  202. //      assumed that the calling function took care of everything before
  203. //      calling this function.
  204. //
  205. //  Arguments:
  206. //      HWND hwnd: Handle to main window.
  207. //
  208. //      PTSTR pszFilePath: Pointer to null terminated file path to open as
  209. //      an MCI script. This buffer will be returned with a fully qualified
  210. //      path of the file that was opened (if successful).
  211. //
  212. //      PTSTR pszFileTitle: Pointer to buffer to receive the file title of
  213. //      the newly opened file. This buffer does not need to be initialized.
  214. //
  215. //  Return (BOOL):
  216. //      The return value is TRUE if the function is successful. It is FALSE
  217. //      if an error occurred. If an error does occur, then the contents
  218. //      of the script window, pszFilePath and pszFileTitle will remain
  219. //      unchanged.
  220. //
  221. //  History:
  222. //       2/ 6/93    created.
  223. //
  224. //--------------------------------------------------------------------------;
  225.  
  226. BOOL FNGLOBAL MciAppFileOpen
  227. (
  228.     HWND            hwnd,
  229.     PTSTR           pszFilePath,
  230.     PTSTR           pszFileTitle
  231. )
  232. {
  233. #ifdef UNICODE
  234.     HANDLE      hf;
  235. #else
  236.     #define SEEK_SET        0       // flags for _lseek
  237.     #define SEEK_CUR        1
  238.     #define SEEK_END        2
  239.  
  240.     HFILE       hf;
  241.     OFSTRUCT    of;
  242. #endif
  243.     HWND        hwndScript;
  244.     UINT        uFileLen;
  245.     LPTSTR      psz;
  246.     BOOL        fReturn;
  247.  
  248.     //
  249.     //  open the file for reading..
  250.     //
  251. #ifdef UNICODE
  252.     hf = CreateFile(pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
  253.                     OPEN_EXISTING, 0, 0);
  254.     if (INVALID_HANDLE_VALUE == hf)
  255.         return (FALSE);
  256. #else
  257.     of.cBytes = sizeof(of);
  258.     hf = OpenFile(pszFilePath, &of, OF_READ);
  259.     if (HFILE_ERROR == hf)
  260.         return (FALSE);
  261. #endif
  262.  
  263.     //
  264.     //  assume the worst
  265.     //
  266.     fReturn = FALSE;
  267.  
  268.     //
  269.     //  determine the length in _bytes_ of the file--note that win 16 is
  270.     //  limited to 32k so big files get truncated... improperly.
  271.     //
  272.     //  !!! need to handle files that are too big better !!!
  273.     //
  274. #ifdef WIN32
  275.     uFileLen = (UINT)GetFileSize((HANDLE)hf, NULL);
  276. #else
  277.     uFileLen = (UINT)_llseek(hf, 0L, SEEK_END);
  278.     _llseek(hf, 0L, SEEK_SET);
  279. #endif
  280.  
  281.  
  282.     //
  283.     //  now read the contents of the file into a buffer--display an hour
  284.     //  glass in case the file is large and/or we are reading from a slow
  285.     //  device... note that the memory allocation may take some time if
  286.     //  the pager is in meltdown mode.
  287.     //
  288.     AppHourGlass(TRUE);
  289.     for (;;)
  290.     {
  291.         //
  292.         //  allocate enough memory to hold the complete image of the file
  293.         //  plus one character for good measure (the forced null termination
  294.         //  could fault if don't add one char to size).
  295.         //
  296.         psz = GlobalAllocPtr(GMEM_MOVEABLE, uFileLen + sizeof(TCHAR));
  297.         if (NULL == psz)
  298.             break;
  299.  
  300.         //
  301.         //  read the file and copy the contents into the script window
  302.         //
  303. #ifdef UNICODE
  304.         fReturn = ReadFile(hf, psz, uFileLen, (LPDWORD)&uFileLen, NULL);
  305.         if (!fReturn)
  306.             break;
  307. #else
  308.         uFileLen = _lread(hf, psz, uFileLen);
  309.         if ((UINT)-1 == uFileLen)
  310.             break;
  311. #endif
  312.  
  313.         //
  314.         //  make sure the text gets null terminated, then shove it into
  315.         //  the script window.
  316.         //
  317.         psz[uFileLen / sizeof(TCHAR)] = '\0';
  318.  
  319.         hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  320. #ifdef UNICODE
  321.         //
  322.         //  determine whether the text is Unicode or ANSI: Unicode files
  323.         //  all start with a Byte Order Mark (BOM) that will be 0xFEFF in
  324.         //  the proper Endian for the file.
  325.         //
  326.         //  !!! this application only deals with ANSI and Little Endian
  327.         //      Unicode files--should handle more gracefully if not...
  328.         //
  329.         if ((uFileLen >= sizeof(TCHAR)) && (psz[0] == 0xFEFF))
  330.         {
  331.             //
  332.             //  set the window text as Unicode--note that we do not send
  333.             //  the BOM, the edit control doesn't want it...
  334.             //
  335.             gfuAppOptions |= APP_OPTF_UNICODE;
  336.             SetWindowTextW(hwndScript, (LPCWSTR)&psz[1]);
  337.         }
  338.         else
  339.         {
  340.             gfuAppOptions &= ~APP_OPTF_UNICODE;
  341.             SetWindowTextA(hwndScript, (LPCSTR)psz);
  342.         }
  343. #else
  344.         SetWindowText(hwndScript, (LPCTSTR)psz);
  345. #endif
  346.  
  347.         //
  348.         //  now return the fully qualified path and title for the file
  349.         //!!!
  350. #ifndef UNICODE
  351.         lstrcpy(pszFilePath, of.szPathName);
  352. #endif
  353.         if (NULL != pszFileTitle)
  354.         {
  355.             AppGetFileTitle(pszFilePath, pszFileTitle);
  356.         }
  357.  
  358.         fReturn = TRUE;
  359.         break;
  360.     }
  361.     AppHourGlass(FALSE);
  362.  
  363.  
  364.     //
  365.     //  free memory (if allocated) and close the file. return the result
  366.     //  of our attempt...
  367.     //
  368.     if (psz)
  369.         GlobalFreePtr(psz);
  370.  
  371. #ifdef UNICODE
  372.     CloseHandle(hf);
  373. #else
  374.     _lclose(hf);
  375. #endif
  376.  
  377.  
  378.     //
  379.     //  !!! before returning, we really should try to display a error
  380.     //      message... memory error, etc..
  381.     //
  382.     return (fReturn);
  383. } // MciAppFileOpen()
  384.  
  385.  
  386. //--------------------------------------------------------------------------;
  387. //
  388. //  BOOL MciAppFileSave
  389. //
  390. //  Description:
  391. //      This function saves the current script to the specified file.
  392. //
  393. //      NOTE! This function does NOT bring up a save file chooser dialog
  394. //      if the file path is invalid. The calling function is responsible
  395. //      for making sure the file path is valid before calling this function.
  396. //
  397. //      This function also does NOT modify the 'modified' bit of the script
  398. //      window. This is up to the calling function.
  399. //
  400. //  Arguments:
  401. //      HWND hwnd: Handle to main window.
  402. //
  403. //      PCTSTR pszFilePath: Pointer to null terminated file path to save
  404. //      the script to.
  405. //
  406. //  Return (BOOL):
  407. //      The return value is TRUE if the function is successful. It is FALSE
  408. //      if an error occurred. If an error does occur, then the contents
  409. //      of the script window was not saved.
  410. //
  411. //  History:
  412. //       2/ 6/93    created.
  413. //
  414. //--------------------------------------------------------------------------;
  415.  
  416. BOOL FNGLOBAL MciAppFileSave
  417. (
  418.     HWND            hwnd,
  419.     PCTSTR          pszFilePath
  420. )
  421. {
  422. #ifdef UNICODE
  423.     HANDLE      hf;
  424. #else
  425.     HFILE       hf;
  426.     OFSTRUCT    of;
  427. #endif
  428.     HWND        hwndScript;
  429.     UINT        uFileLen;
  430.     DWORD       cbBytes;
  431.     LPTSTR      psz;
  432.     BOOL        fReturn;
  433.  
  434.     //
  435.     //  create the new file--if it already exists, this will open and init
  436.     //  it to zero length.
  437.     //
  438. #ifdef UNICODE
  439.     hf = CreateFile(pszFilePath, GENERIC_WRITE, FILE_SHARE_READ,
  440.                     NULL, CREATE_ALWAYS, 0, 0);
  441.     if (INVALID_HANDLE_VALUE == hf)
  442.         return (FALSE);
  443. #else
  444.     of.cBytes = sizeof(of);
  445.     hf = OpenFile(pszFilePath, &of, OF_CREATE);
  446.     if (HFILE_ERROR == hf)
  447.         return (FALSE);
  448. #endif
  449.  
  450.     //
  451.     //  assume the worst
  452.     //
  453.     fReturn = FALSE;
  454.  
  455.     //
  456.     //  get the length in bytes of the script--we add 1 to the result
  457.     //  because GetWindowTextLength returns the length in bytes NOT including
  458.     //  the null terminator.
  459.     //
  460.     //  !!! UNICODE !!!
  461.     //
  462.     hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  463.     uFileLen = (UINT)GetWindowTextLength(hwndScript) + 1;
  464.  
  465.     //!!! nFileLen = nFileLen*sizeof(TCHAR);  We write ASCII
  466.  
  467.     //
  468.     //  allocate a buffer to hold the script text, get the text, and write
  469.     //  it out. display an hour glass in case the file is large and/or we
  470.     //  are writing to a slow device...
  471.     //
  472.     AppHourGlass(TRUE);
  473.     for (;;)
  474.     {
  475.         //
  476.         //  allocate enough memory to hold the complete image of the script
  477.         //
  478.         psz = GlobalAllocPtr(GMEM_MOVEABLE, uFileLen + sizeof(TCHAR));
  479.         if (NULL == psz)
  480.             break;
  481.  
  482.         //
  483.         //  read the contents of the script window and write it to the
  484.         //  new file
  485.         //
  486. #ifdef UNICODE
  487.         // !!!! Save ASCII file
  488.         GetWindowTextA(hwndScript, (LPSTR)psz, uFileLen);
  489.         WriteFile(hf, psz, uFileLen, &cbBytes, NULL);
  490. #else
  491.         GetWindowText(hwndScript, (LPTSTR)psz, uFileLen);
  492.         cbBytes = (DWORD)_lwrite(hf, (LPSTR)psz, uFileLen);
  493. #endif
  494.  
  495.         //
  496.         //  succeed
  497.         //
  498.         fReturn = TRUE;
  499.         break;
  500.     }
  501.     AppHourGlass(FALSE);
  502.  
  503.  
  504.     //
  505.     //  free memory (if allocated) and close the file. return the result
  506.     //  of our attempt...
  507.     //
  508.     if (psz)
  509.         GlobalFreePtr(psz);
  510.  
  511. #ifdef UNICODE
  512.     CloseHandle(hf);
  513. #else
  514.     _lclose(hf);
  515. #endif
  516.  
  517.  
  518.     //
  519.     //  !!! before returning, we really should try to display an error
  520.     //      message... memory error, etc..
  521.     //
  522.     return (fReturn);
  523. } // MciAppFileSave()
  524.  
  525.  
  526. //==========================================================================;
  527. //
  528. //  MCI Device List stuff
  529. //
  530. //
  531. //
  532. //==========================================================================;
  533.  
  534. //--------------------------------------------------------------------------;
  535. //
  536. //  UINT MciAppGetNumDevices
  537. //
  538. //  Description:
  539. //      This function sends a command to MCI querying it as to how many
  540. //      devices are currently open in the system. This number is the
  541. //      return value.
  542. //
  543. //  Arguments:
  544. //      HWND hwnd: Handle to main window.
  545. //
  546. //  Return (UINT):
  547. //      Returns the number of currently open MCI devices in the system.
  548. //
  549. //  History:
  550. //       2/ 7/93    created.
  551. //
  552. //--------------------------------------------------------------------------;
  553.  
  554. UINT FNGLOBAL MciAppGetNumDevices
  555. (
  556.     HWND            hwnd
  557. )
  558. {
  559.     MCI_SYSINFO_PARMS   msip;
  560.     MCIERROR            mciError;
  561.     DWORD               dwDevices;
  562.  
  563.     //
  564.     //  set things up so that MCI puts the number of open devices directly
  565.     //  into dwDevices
  566.     //
  567.     msip.lpstrReturn = (LPVOID)&dwDevices;
  568.     msip.dwRetSize   = sizeof(dwDevices);
  569.  
  570.     //
  571.     //  ask MCI how many open devices are in the system--if this errors
  572.     //  then return 0...
  573.     //
  574.     mciError = mciSendCommand(MCI_ALL_DEVICE_ID,
  575.                               MCI_SYSINFO,
  576.                               MCI_SYSINFO_OPEN | MCI_SYSINFO_QUANTITY,
  577.                               (DWORD)(LPVOID)&msip);
  578.  
  579.     if (MMSYSERR_NOERROR == mciError)
  580.         return ((UINT)dwDevices);
  581.  
  582.     return (0);
  583. } // MciAppGetNumDevices()
  584.  
  585.  
  586. //--------------------------------------------------------------------------;
  587. //
  588. //  BOOL MciAppDeviceListUpdate
  589. //
  590. //  Description:
  591. //      This function updates the MCI Device List window if it is displayed.
  592. //
  593. //  Arguments:
  594. //      HWND hwnd: Handle to main window.
  595. //
  596. //      BOOL fForceUpdate: Forces the list to be updated even if number
  597. //      of devices has not changed.
  598. //
  599. //  Return (BOOL):
  600. //      Returns TRUE if the device list needed to be updated. FALSE if
  601. //      the list was fine...
  602. //
  603. //  History:
  604. //       2/ 7/93    created.
  605. //
  606. //--------------------------------------------------------------------------;
  607.  
  608. BOOL FNLOCAL MciAppDeviceListUpdate
  609. (
  610.     HWND            hwnd,
  611.     HWND            hwndDevices,
  612.     BOOL            fForceUpdate
  613. )
  614. {
  615.     static TCHAR    szFormatDevice[]    = TEXT("%2d. '%s'");
  616.     static UINT     uLastNumDevices;
  617.  
  618.     TCHAR               ach[APP_MAX_STRING_RC_CHARS];
  619.     TCHAR               szDevName[APP_MAX_STRING_RC_CHARS];
  620.     MCI_SYSINFO_PARMS   msip;
  621.     MCIERROR            mciError;
  622.     HWND                hwndList;
  623.     UINT                uNumDevs;
  624.     UINT                u;
  625.  
  626.     //
  627.     //  if the devices window is not displayed, then fail..
  628.     //
  629.     if (NULL == hwndDevices)
  630.         return (FALSE);
  631.  
  632.     uNumDevs = MciAppGetNumDevices(hwnd);
  633.  
  634.     //
  635.     //  if not being forced to update list, then make a quick check to
  636.     //  see if we should update the list...
  637.     //
  638.     if (!fForceUpdate && (uNumDevs == uLastNumDevices))
  639.         return (FALSE);
  640.  
  641.     //
  642.     //  really update the device list...
  643.     //
  644.     uLastNumDevices = uNumDevs;
  645.  
  646.     //
  647.     //  initialize the devices listbox...
  648.     //
  649.     hwndList = GetDlgItem(hwndDevices, IDD_MCIDEVS_LIST_OPEN);
  650.     ListBox_ResetContent(hwndList);
  651.  
  652.     SetWindowRedraw(hwndList, FALSE);
  653.  
  654.     //
  655.     //  get the name of each open device in the system and add it to the
  656.     //  device list box...
  657.     //
  658.     for (u = 1; u <= uNumDevs; ++u)
  659.     {
  660.         msip.dwNumber    = u;
  661.         msip.lpstrReturn = (LPVOID)&szDevName;
  662.         msip.dwRetSize   = SIZEOF(szDevName);
  663.  
  664.         //
  665.         //  get the name--if an error is encountered, then skip to the
  666.         //  next device...
  667.         //
  668.         mciError = mciSendCommand(MCI_ALL_DEVICE_ID,
  669.                                   MCI_SYSINFO,
  670.                                   MCI_SYSINFO_OPEN | MCI_SYSINFO_NAME,
  671.                                   (DWORD)(LPVOID)&msip);
  672.  
  673.         if (MMSYSERR_NOERROR != mciError)
  674.             continue;
  675.  
  676.         //
  677.         //  add the device name to the listbox..
  678.         //
  679.         wsprintf(ach, szFormatDevice, u, (LPSTR)szDevName);
  680.         ListBox_AddString(hwndList, ach);
  681.     }
  682.  
  683.     if (0 != uNumDevs)
  684.         ListBox_SetCurSel(hwndList, 0);
  685.  
  686.     SetWindowRedraw(hwndList, TRUE);
  687.     InvalidateRect(hwndList, NULL, TRUE);
  688.  
  689.     //
  690.     //  set the info button to the correct state: enabled if there are
  691.     //  devices open--disabled if no devices are open.
  692.     //
  693.     EnableWindow(GetDlgItem(hwndDevices, IDD_MCIDEVS_BTN_INFO), 0 != uNumDevs);
  694.  
  695.     return (TRUE);
  696. } // MciAppDeviceListUpdate()
  697.  
  698.  
  699. //--------------------------------------------------------------------------;
  700. //
  701. //  BOOL MciAppCloseAllDevices
  702. //
  703. //  Description:
  704. //      This function sends the MCI command "close all" and then updates
  705. //      the displayed info for the application.
  706. //
  707. //  Arguments:
  708. //      HWND hwnd: Handle to main window.
  709. //
  710. //  Return (BOOL):
  711. //      Always returns TRUE.
  712. //
  713. //  History:
  714. //       2/ 8/93    created.
  715. //
  716. //--------------------------------------------------------------------------;
  717.  
  718. BOOL FNGLOBAL MciAppCloseAllDevices
  719. (
  720.     HWND            hwnd
  721. )
  722. {
  723.     static TCHAR    szCloseAll[]    = TEXT("close all");
  724.  
  725.     //
  726.     //  close all open devices and update the device list if it is being
  727.     //  displayed...
  728.     //
  729.     mciSendString(szCloseAll, NULL, 0, NULL);
  730.     MciAppDeviceListUpdate(hwnd, ghwndDevices, FALSE);
  731.  
  732.     return (TRUE);
  733. } // MciAppCloseAllDevices()
  734.  
  735.  
  736. //--------------------------------------------------------------------------;
  737. //
  738. //  BOOL MciAppDeviceDlgProc
  739. //
  740. //  Description:
  741. //      Callback function for the dialog box which displays a list of the
  742. //      currently opened MCI devices.
  743. //
  744. //  Arguments:
  745. //      HWND hwnd: Handle to window.
  746. //
  747. //      UINT uMsg: Message being sent to the window.
  748. //
  749. //      WPARAM wParam: Specific argument to message.
  750. //
  751. //      LPARAM lParam: Specific argument to message.
  752. //
  753. //  Return (BOOL):
  754. //      The return value is specific to the message that was received. For
  755. //      the most part, it is FALSE if this dialog procedure does not handle
  756. //      a message.
  757. //
  758. //  History:
  759. //       2/ 7/93    created.
  760. //
  761. //--------------------------------------------------------------------------;
  762.  
  763. BOOL FNEXPORT MciAppDeviceDlgProc
  764. (
  765.     HWND            hwnd,
  766.     UINT            uMsg,
  767.     WPARAM          wParam,
  768.     LPARAM          lParam
  769. )
  770. {
  771.     RECT    rcApp;
  772.     RECT    rc;
  773.     HFONT   hfont;
  774.     HWND    hwndParent;
  775.     UINT    u;
  776.     int     n;
  777.  
  778.     switch (uMsg)
  779.     {
  780.         case WM_INITDIALOG:
  781.             //
  782.             //  move the window so it sits in the upper right corner of the
  783.             //  main window by default...
  784.             //
  785.             GetWindowRect(GetParent(hwnd), &rcApp);
  786.             GetWindowRect(hwnd, &rc);
  787.  
  788.             n = (int)(rc.right - rc.left);
  789.             rc.left = rcApp.right - n - 30;
  790.             MoveWindow(hwnd, (int)rc.left, (int)rc.top,
  791.                        n, (int)(rc.bottom - rc.top), FALSE);
  792.  
  793.             //
  794.             //
  795.             //
  796.             hfont = GetStockFont(SYSTEM_FIXED_FONT);
  797.             SetWindowFont(GetDlgItem(hwnd, IDD_MCIDEVS_LIST_OPEN), hfont, FALSE);
  798.  
  799.             //
  800.             //  update the information displayed in the listbox
  801.             //
  802.             MciAppDeviceListUpdate(GetParent(hwnd), hwnd, TRUE);
  803.  
  804.             return (TRUE);
  805.  
  806.         case WM_COMMAND:
  807.             u = GET_WM_COMMAND_ID(wParam, lParam);
  808.             switch (u)
  809.             {
  810.                 case IDCANCEL:
  811.                 case IDOK:
  812.                     //
  813.                     //  return button id of the one that was pressed...
  814.                     //
  815.                     hwndParent = GetParent(hwnd);
  816.                     EndDialog(hwnd, u);
  817.  
  818.                     ghwndDevices = NULL;
  819.                     gfuAppOptions &= ~APP_OPTF_DEVICELIST;
  820.                     SetFocus(GetDlgItem(hwndParent, IDD_APP_EDIT_SCRIPT));
  821.                     break;
  822.  
  823.                 case IDD_MCIDEVS_BTN_INFO:
  824.                     n = ListBox_GetCurSel(GetDlgItem(hwnd, IDD_MCIDEVS_LIST_OPEN));
  825.                     if (LB_ERR == n)
  826.                         break;
  827.  
  828.                     break;
  829.             }
  830.             break;
  831.     }
  832.  
  833.     return (FALSE);
  834. } // MciAppDeviceDlgProc()
  835.  
  836.  
  837. //--------------------------------------------------------------------------;
  838. //
  839. //  BOOL MciAppDeviceList
  840. //
  841. //  Description:
  842. //      This function either displays or destroys the MCI device list
  843. //      window.
  844. //
  845. //  Arguments:
  846. //      HWND hwnd: Handle to main window.
  847. //
  848. //      BOOL fActivate: TRUE if the device list window should keep
  849. //      the activation. FALSE if the current active window should remain
  850. //      active.
  851. //
  852. //  Return (BOOL):
  853. //      The return value is TRUE if the device list is displayed. It is
  854. //      FALSE if the device list has been canceled/closed.
  855. //
  856. //  History:
  857. //       2/ 7/93    created.
  858. //
  859. //--------------------------------------------------------------------------;
  860.  
  861. BOOL FNGLOBAL MciAppDeviceList
  862. (
  863.     HWND            hwnd,
  864.     BOOL            fActivate
  865. )
  866. {
  867.     HWND        hwndFocus;
  868.  
  869.     //
  870.     //  should we display or destroy it?
  871.     //
  872.     if (0 != (gfuAppOptions & APP_OPTF_DEVICELIST))
  873.     {
  874.         if (NULL != ghwndDevices)
  875.             return (TRUE);
  876.  
  877.         hwndFocus = GetFocus();
  878.  
  879.         ghwndDevices = CreateDialog(ghinst, DLG_MCIDEVS, hwnd, (DLGPROC)MciAppDeviceDlgProc);
  880.         if (NULL  == ghwndDevices)
  881.         {
  882.             gfuAppOptions &= ~APP_OPTF_DEVICELIST;
  883.             return (FALSE);
  884.         }
  885.  
  886.         //
  887.         //  note that the window will 'flash' because we used CreateDialog
  888.         //  when creating the device list window. we keep the flash to
  889.         //  a minimum by creating the device window hidden and then showing
  890.         //  it... if you want to get rid of the flash completely, then
  891.         //  use CreateWindow and write a lot more code.
  892.         //
  893.         if (fActivate)
  894.         {
  895.             ShowWindow(ghwndDevices, SW_SHOW);
  896.         }
  897.         else
  898.         {
  899.             SetActiveWindow(hwnd);
  900.             SetFocus(hwndFocus);
  901.             ShowWindow(ghwndDevices, SW_SHOWNA);
  902.         }
  903.  
  904.         return (TRUE);
  905.     }
  906.     else
  907.     {
  908.         if (NULL != ghwndDevices)
  909.         {
  910.             EndDialog(ghwndDevices, IDOK);
  911.             ghwndDevices = NULL;
  912.         }
  913.  
  914.         return (FALSE);
  915.     }
  916. } // MciAppDeviceList()
  917.  
  918.  
  919. //==========================================================================;
  920. //
  921. //
  922. //
  923. //
  924. //==========================================================================;
  925.  
  926. //--------------------------------------------------------------------------;
  927. //
  928. //  BOOL MciAppUpdateOptions
  929. //
  930. //  Description:
  931. //      This function updates the options status window to reflect the
  932. //      current status of the options.
  933. //
  934. //  Arguments:
  935. //      HWND hwnd: Handle to main window.
  936. //
  937. //  Return (BOOL):
  938. //      Always returns TRUE.
  939. //
  940. //  History:
  941. //       2/ 8/93    created.
  942. //
  943. //--------------------------------------------------------------------------;
  944.  
  945. BOOL FNGLOBAL MciAppUpdateOptions
  946. (
  947.     HWND            hwnd
  948. )
  949. {
  950. #ifdef UNICODE
  951.     static TCHAR    szFormatOptions[]   = TEXT("%c%c%c%c");
  952. #else
  953.     static TCHAR    szFormatOptions[]   = TEXT("%c%c%c");
  954. #endif
  955.  
  956.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  957.  
  958.     //
  959.     //  format an appropriate string for the options
  960.     //
  961.     wsprintf(ach, szFormatOptions,
  962. #ifdef UNICODE
  963.              (0 != (gfuAppOptions & APP_OPTF_UNICODE))   ? 'U' : '-',
  964. #endif
  965.              (0 != (gfuAppOptions & APP_OPTF_EDITONLY))  ? 'E' : '-',
  966.              (0 != (gfuAppOptions & APP_OPTF_YIELDEXEC)) ? 'Y' : '-',
  967.              (0 != (gfuAppOptions & APP_OPTF_DEBUGLOG))  ? 'L' : '-');
  968.  
  969.     SetWindowText(GetDlgItem(hwnd, IDD_APP_TEXT_OPTIONS), ach);
  970.  
  971.     return (TRUE);
  972. } // MciAppUpdateOptions()
  973.  
  974.  
  975. //--------------------------------------------------------------------------;
  976. //
  977. //  BOOL MciAppResetStatus
  978. //
  979. //  Description:
  980. //      This function resets all of the status windows (status, notify,
  981. //      and output). This is used when a new script is created/opened.
  982. //
  983. //  Arguments:
  984. //      HWND hwnd: Handle to main window.
  985. //
  986. //  Return (BOOL):
  987. //      Always returns TRUE.
  988. //
  989. //  History:
  990. //       2/ 7/93    created.
  991. //
  992. //--------------------------------------------------------------------------;
  993.  
  994. BOOL FNGLOBAL MciAppResetStatus
  995. (
  996.     HWND            hwnd
  997. )
  998. {
  999.     //
  1000.     //  nuke all status text...
  1001.     //
  1002.     SetWindowText(GetDlgItem(hwnd, IDD_APP_TEXT_OUTPUT), gszNone);
  1003.     SetWindowText(GetDlgItem(hwnd, IDD_APP_TEXT_STATUS), gszNull);
  1004.     SetWindowText(GetDlgItem(hwnd, IDD_APP_TEXT_NOTIFY), gszNull);
  1005.  
  1006.     MciAppUpdateOptions(hwnd);
  1007.  
  1008.     return (TRUE);
  1009. } // MciAppResetStatus()
  1010.  
  1011.  
  1012. //--------------------------------------------------------------------------;
  1013. //
  1014. //  void MciAppDebugLog
  1015. //
  1016. //  Description:
  1017. //      This function logs information to the debugger if the Debug Log
  1018. //      option is set. You can then run DBWin (or something similar)
  1019. //      to redirect the output whereever you want. Very useful for debugging
  1020. //      MCI drivers.
  1021. //
  1022. //  Arguments:
  1023. //      PCTSTR pszFormat: Pointer to any valid format for wsprintf.
  1024. //
  1025. //  Return (void):
  1026. //      None.
  1027. //
  1028. //  History:
  1029. //       2/ 7/93    created.
  1030. //
  1031. //--------------------------------------------------------------------------;
  1032.  
  1033. void FNCGLOBAL MciAppDebugLog
  1034. (
  1035.     PCTSTR          pszFormat,
  1036.     ...
  1037. )
  1038. {
  1039.     va_list     va;
  1040.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  1041.  
  1042.  
  1043.     //
  1044.     //  !!! UNICODE !!!
  1045.     //
  1046.     //
  1047.     if (0 != (gfuAppOptions & APP_OPTF_DEBUGLOG))
  1048.     {
  1049.         //
  1050.         //  format and display the string in a message box...
  1051.         //
  1052.         va_start(va, pszFormat);
  1053.         wvsprintf(ach, pszFormat, va);
  1054.         va_end(va);
  1055.  
  1056.         OutputDebugString(gszAppName);
  1057.         OutputDebugString(TEXT(": "));
  1058.         OutputDebugString(ach);
  1059.         OutputDebugString(TEXT("\r\n"));
  1060.     }
  1061. } // MciAppDebugLog()
  1062.  
  1063.  
  1064. //--------------------------------------------------------------------------;
  1065. //
  1066. //  BOOL MciAppHandleNotify
  1067. //
  1068. //  Description:
  1069. //      This function handles displaying the notification message from
  1070. //      commands sent with the 'notify' option.
  1071. //
  1072. //  Arguments:
  1073. //      HWND hwnd: Handle to main window.
  1074. //
  1075. //      UINT fuNotify: Notification flags (wParam) from MM_MCINOTIFY message.
  1076. //
  1077. //      UINT uId: Device id sending notification.
  1078. //
  1079. //  Return (BOOL):
  1080. //      Always returns TRUE.
  1081. //
  1082. //  History:
  1083. //       2/ 7/93    created.
  1084. //
  1085. //--------------------------------------------------------------------------;
  1086.  
  1087. BOOL FNGLOBAL MciAppHandleNotify
  1088. (
  1089.     HWND            hwnd,
  1090.     UINT            fuNotify,
  1091.     UINT            uId
  1092. )
  1093. {
  1094.     static TCHAR    szFormatNotify[]        = TEXT("Notify(%u,%u): %s");
  1095.     static TCHAR    szDBFormatNotify[]      = TEXT("    MCI Notify: Id=%u, Flag(%u)='%s'");
  1096.  
  1097.     HWND        hwndNotify;
  1098.     TCHAR       ach[APP_MAX_STRING_RC_CHARS];
  1099.     UINT        uIds;
  1100.  
  1101.     //
  1102.     //
  1103.     //
  1104.     //
  1105.     switch (fuNotify)
  1106.     {
  1107.         case MCI_NOTIFY_SUCCESSFUL:
  1108.             uIds = IDS_MCI_NOTIFY_SUCCESSFUL;
  1109.             break;
  1110.  
  1111.         case MCI_NOTIFY_SUPERSEDED:
  1112.             uIds = IDS_MCI_NOTIFY_SUPERSEDED;
  1113.             break;
  1114.  
  1115.         case MCI_NOTIFY_ABORTED:
  1116.             uIds = IDS_MCI_NOTIFY_ABORTED;
  1117.             break;
  1118.  
  1119.         case MCI_NOTIFY_FAILURE:
  1120.             uIds = IDS_MCI_NOTIFY_FAILURE;
  1121.             break;
  1122.  
  1123.         default:
  1124.             uIds = IDS_MCI_NOTIFY_UNKNOWN;
  1125.             break;
  1126.     }
  1127.  
  1128.     LoadString(ghinst, uIds, ach, SIZEOF(ach));
  1129.     hwndNotify = GetDlgItem(hwnd, IDD_APP_TEXT_NOTIFY);
  1130.     AppSetWindowText(hwndNotify, szFormatNotify, uId, fuNotify, (LPSTR)ach);
  1131.  
  1132.     //
  1133.     //  !!! UNICODE !!!
  1134.     //
  1135.     MciAppDebugLog(szDBFormatNotify, uId, fuNotify, (LPSTR)ach);
  1136.  
  1137.     return (TRUE);
  1138. } // MciAppHandleNotify()
  1139.  
  1140.  
  1141. //--------------------------------------------------------------------------;
  1142. //
  1143. //  BOOL MciAppErrorDlgProc
  1144. //
  1145. //  Description:
  1146. //      Callback function for the dialog box which occurs during the
  1147. //      execution of an error in a loop of script commands. It displays
  1148. //      Abort, Continue and Ignore buttons.
  1149. //
  1150. //  Arguments:
  1151. //      HWND hwnd: Handle to window.
  1152. //
  1153. //      UINT uMsg: Message being sent to the window.
  1154. //
  1155. //      WPARAM wParam: Specific argument to message.
  1156. //
  1157. //      LPARAM lParam: Specific argument to message.
  1158. //
  1159. //  Return (BOOL):
  1160. //      The return value is specific to the message that was received. For
  1161. //      the most part, it is FALSE if this dialog procedure does not handle
  1162. //      a message.
  1163. //
  1164. //  History:
  1165. //       2/ 7/93    created.
  1166. //
  1167. //--------------------------------------------------------------------------;
  1168.  
  1169. BOOL FNEXPORT MciAppErrorDlgProc
  1170. (
  1171.     HWND            hwnd,
  1172.     UINT            uMsg,
  1173.     WPARAM          wParam,
  1174.     LPARAM          lParam
  1175. )
  1176. {
  1177.     UINT    u;
  1178.  
  1179.     switch (uMsg)
  1180.     {
  1181.         case WM_INITDIALOG:
  1182.             return (TRUE);
  1183.  
  1184.         case WM_COMMAND:
  1185.             u = GET_WM_COMMAND_ID(wParam, lParam);
  1186.             switch (u)
  1187.             {
  1188.                 case IDABORT:
  1189.                 case IDOK:
  1190.                 case IDIGNORE:
  1191.                     //
  1192.                     //  return button id of the one that was pressed...
  1193.                     //
  1194.                     EndDialog(hwnd, u);
  1195.                     break;
  1196.             }
  1197.             break;
  1198.     }
  1199.  
  1200.     return (FALSE);
  1201. } // MciAppErrorDlgProc()
  1202.  
  1203.  
  1204. //--------------------------------------------------------------------------;
  1205. //
  1206. //  MCIERROR MciAppSendString
  1207. //
  1208. //  Description:
  1209. //      Sends the specified string command to an MCI device via the MCI
  1210. //      string interface. Any return strings from MCI devices are displayed
  1211. //      in the 'Output' text box. Error values are displayed in the status
  1212. //      bar.
  1213. //
  1214. //  Arguments:
  1215. //      HWND hwnd: Handle to main window.
  1216. //
  1217. //      PCTSTR pszCommand: Pointer to the string command to be executed.
  1218. //
  1219. //  Return (MCIERROR):
  1220. //      The return value is the result of the mciSendString() function.
  1221. //
  1222. //  History:
  1223. //       2/ 7/93    created.
  1224. //
  1225. //--------------------------------------------------------------------------;
  1226.  
  1227. MCIERROR FNGLOBAL MciAppSendString
  1228. (
  1229.     HWND            hwnd,
  1230.     PCTSTR          pszCommand
  1231. )
  1232. {
  1233.     static TCHAR    szFormatDBSendString[]  = TEXT("mciSendString('%s')");
  1234.     static TCHAR    szFormatOutput[]        = TEXT("'%s'");
  1235.     static TCHAR    szFormatDBOutput[]      = TEXT("    MCI Output: '%s'");
  1236.     static TCHAR    szFormatError[]         = TEXT("MCI Error: [%lu], %s");
  1237.     static TCHAR    szFormatDBError[]       = TEXT("    MCI Error : [%lu], '%s'");
  1238.  
  1239.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  1240.     HWND        hwndOutput;
  1241.     HWND        hwndStatus;
  1242.     MCIERROR    mciError;
  1243.  
  1244.     //
  1245.     //  reset the notify window text..
  1246.     //
  1247.     SetWindowText(GetDlgItem(hwnd, IDD_APP_TEXT_NOTIFY), gszNull);
  1248.  
  1249.  
  1250.     //
  1251.     //  send the string command to MCI--capture the return value and have
  1252.     //  the notification code go to the main window (MM_MCINOTIFY)...
  1253.     //
  1254.     //  !!! UNICODE !!!
  1255.     //
  1256.     MciAppDebugLog(szFormatDBSendString, (LPSTR)pszCommand);
  1257.     mciError = mciSendString(pszCommand, ach, SIZEOF(ach), hwnd);
  1258.  
  1259.     //
  1260.     //  if the command errored, then beep the _speaker_ (-1). don't want
  1261.     //  to use wave devices because many mci scripts use them..
  1262.     //
  1263.     if (MMSYSERR_NOERROR != mciError)
  1264.         MessageBeep((UINT)-1);
  1265.  
  1266.     MciAppDebugLog(szFormatDBOutput, (LPSTR)ach);
  1267.  
  1268.     //
  1269.     //  put the text message returned by MCI into the 'Output' box
  1270.     //
  1271.     hwndOutput = GetDlgItem(hwnd, IDD_APP_TEXT_OUTPUT);
  1272.     if ('\0' == ach[0])
  1273.         SetWindowText(hwndOutput, gszNone);
  1274.     else
  1275.         AppSetWindowText(hwndOutput, szFormatOutput, (LPSTR)ach);
  1276.  
  1277.  
  1278.     //
  1279.     //  decode the error number returned by MCI and display the string in
  1280.     //  the status bar...
  1281.     //
  1282.     //  !!! UNICODE !!!
  1283.     //
  1284.     mciGetErrorString(mciError, ach, SIZEOF(ach));
  1285.     MciAppDebugLog(szFormatDBError, mciError, (LPSTR)ach);
  1286.  
  1287.     hwndStatus = GetDlgItem(hwnd, IDD_APP_TEXT_STATUS);
  1288.     AppSetWindowText(hwndStatus, szFormatError, mciError, (LPSTR)ach);
  1289.  
  1290.  
  1291.     //
  1292.     //  update our list of currently open devices and stuff...
  1293.     //
  1294.     MciAppDeviceListUpdate(hwnd, ghwndDevices, FALSE);
  1295.  
  1296.     return (mciError);
  1297. } // MciAppSendString()
  1298.  
  1299.  
  1300. //--------------------------------------------------------------------------;
  1301. //
  1302. //  BOOL MciAppGetLine
  1303. //
  1304. //  Description:
  1305. //      Retrieves the contents of line (uLine) from the script window.
  1306. //      The string is placed in the pszLineBuffer. All leading and trailing
  1307. //      spaces (and comments) are removed.
  1308. //
  1309. //  Arguments:
  1310. //      HWND hwndScript: Handle to script window (multiline edit control)
  1311. //      to extract nLine from.
  1312. //
  1313. //      int nLine: Line index (zero based) to retrieve.
  1314. //
  1315. //      PTSTR pszBuffer: Pointer to string buffer to receive nLine's
  1316. //      contents.
  1317. //
  1318. //      UINT cchBuffer: Size of pszBuffer is _characters_.
  1319. //
  1320. //  Return (BOOL):
  1321. //      The return value is TRUE if nLine was extracted from the script
  1322. //      window. The return value is FALSE if nLine is out of range for
  1323. //      the current contents of the script window.
  1324. //
  1325. //  History:
  1326. //       2/ 7/93    created.
  1327. //
  1328. //--------------------------------------------------------------------------;
  1329.  
  1330. BOOL FNLOCAL MciAppGetLine
  1331. (
  1332.     HWND            hwndScript,
  1333.     int             nLine,
  1334.     PTSTR           pszBuffer,
  1335.     UINT            cchBuffer
  1336. )
  1337. {
  1338.     #define IS_SPACE(c)     (' '  == (c) || '\t' == (c))
  1339.     #define IS_EOL(c)       ('\n' == (c) || '\r' == (c))
  1340.     #define IS_WHITE(c)     (IS_SPACE(c) || IS_EOL(c))
  1341.  
  1342.     int     nNumLines;
  1343.  
  1344.     //
  1345.     //  find out how many lines are in the script window--if it is out of
  1346.     //  range then fail....
  1347.     //
  1348.     nNumLines = Edit_GetLineCount(hwndScript);
  1349.     if ((nLine < 0) || (nLine >= nNumLines))
  1350.     {
  1351.         pszBuffer[0] = '\0';
  1352.         return (FALSE);
  1353.     }
  1354.  
  1355.     //
  1356.     //  read the line requested into the string buffer..
  1357.     //
  1358.     cchBuffer = Edit_GetLine(hwndScript, nLine, pszBuffer, cchBuffer);
  1359.  
  1360.  
  1361.     //
  1362.     //  strip trailing spaces
  1363.     //
  1364.     while ((cchBuffer > 0) && IS_WHITE(pszBuffer[cchBuffer - 1]))
  1365.     {
  1366.         cchBuffer--;
  1367.     }
  1368.  
  1369.     pszBuffer[cchBuffer] = '\0';
  1370.  
  1371.     return (TRUE);
  1372. } // MciAppGetLine()
  1373.  
  1374.  
  1375. //--------------------------------------------------------------------------;
  1376. //
  1377. //  BOOL MciAppInternalCommand
  1378. //
  1379. //  Description:
  1380. //
  1381. //
  1382. //  Arguments:
  1383. //
  1384. //
  1385. //  Return (BOOL):
  1386. //
  1387. //
  1388. //  History:
  1389. //       2/20/93    created. 
  1390. //
  1391. //--------------------------------------------------------------------------;
  1392.  
  1393. BOOL FNLOCAL MciAppInternalCommand
  1394. (
  1395.     HWND            hwnd,
  1396.     PTSTR           pszCommandLine,
  1397.     BOOL            fYield
  1398. )
  1399. {
  1400.     static TCHAR    szWhiteToken[]      = " \t\n";
  1401.     static TCHAR    szTokenSleep[]      = "sleep";
  1402.     static TCHAR    szTokenPause[]      = "pause";
  1403.  
  1404.     static TCHAR    szFormatError[]     = TEXT("INTERNAL Error: Command (%s), %s.");
  1405.     static TCHAR    szFormatDBError[]   = TEXT("    ICmd Error: Command (%s), %s.");
  1406.  
  1407.     static TCHAR    szSleepComplete[]   = TEXT("Sleep complete.");
  1408.     static TCHAR    szSleepDBComplete[] = TEXT("      Sleeping:  sleep complete.");
  1409.  
  1410.     static TCHAR    szErrorBadCmd[]     = TEXT("unrecognized command");
  1411.     static TCHAR    szErrorBadParam[]   = TEXT("invalid parameter");
  1412.     static TCHAR    szErrorParamRqd[]   = TEXT("parameter(s) required");
  1413.  
  1414.     static TCHAR    szFormatSleeping[]  = TEXT("Sleeping for %lu %s...");
  1415.     static TCHAR    szSeconds[]         = TEXT("seconds");
  1416.     static TCHAR    szMilliseconds[]    = TEXT("milliseconds");
  1417.     static TCHAR    szMinutes[]         = TEXT("minutes");
  1418.     static TCHAR    szHours[]           = TEXT("hours");
  1419.  
  1420.     PTSTR       pchToken;
  1421.     PTSTR       pchCommand;
  1422.     HWND        hwndStatus;
  1423.     long        l;
  1424.     DWORD       dwSleep;
  1425.     PTSTR       szSleepUnit;
  1426.  
  1427.     //
  1428.     //  parse the internal command line...
  1429.     //
  1430.     pchToken = strtok(pszCommandLine, szWhiteToken);
  1431.     if (NULL == pchToken)
  1432.         return (TRUE);
  1433.  
  1434.     hwndStatus = GetDlgItem(hwnd, IDD_APP_TEXT_STATUS);
  1435.     pchCommand = pchToken;
  1436.  
  1437. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1438. //
  1439. //  sleep x [ms | s | m | h]        (default is milliseconds)
  1440. //  pause x [ms | s | m | h]        (default is milliseconds)
  1441. //
  1442. //
  1443. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1444.  
  1445.     if ((0 == lstrcmpi(pchCommand, szTokenSleep)) ||
  1446.         (0 == lstrcmpi(pchCommand, szTokenPause)))
  1447.     {
  1448.         pchToken = strtok(NULL, szWhiteToken);
  1449.         if (NULL == pchToken)
  1450.         {
  1451.             MessageBeep((UINT)-1);
  1452.             AppSetWindowText(hwndStatus, szFormatError,
  1453.                              (LPSTR)pchCommand, (LPSTR)szErrorParamRqd);
  1454.             MciAppDebugLog(szFormatDBError, (LPSTR)pchCommand,
  1455.                            (LPSTR)szErrorParamRqd);
  1456.             return (TRUE);
  1457.         }
  1458.  
  1459.         //
  1460.         //  assume the first token after sleep/pause command is a
  1461.         //  number--do not allow zero or negative numbers!
  1462.         //
  1463.         l = atol(pchToken);
  1464.         if (0 >= l)
  1465.         {
  1466.             MessageBeep((UINT)-1);
  1467.             AppSetWindowText(hwndStatus, szFormatError,
  1468.                              (LPSTR)pchCommand, (LPSTR)szErrorBadParam);
  1469.             MciAppDebugLog(szFormatDBError, (LPSTR)pchCommand,
  1470.                            (LPSTR)szErrorBadParam);
  1471.             return (TRUE);
  1472.         }
  1473.  
  1474.         //
  1475.         //  now see what unit
  1476.         //
  1477.         dwSleep     = (DWORD)l;
  1478.         szSleepUnit = szMilliseconds;
  1479.         pchToken    = strtok(NULL, szWhiteToken);
  1480.         if (NULL != pchToken)
  1481.         {
  1482.             switch (pchToken[0])
  1483.             {
  1484.                 case 's':
  1485.                 case 'S':
  1486.                     dwSleep *= 1000;
  1487.                     szSleepUnit = szSeconds;
  1488.                     break;
  1489.  
  1490.                 case 'm':
  1491.                 case 'M':
  1492.                     //
  1493.                     //  if unit marker is not 'ms' then assume minutes
  1494.                     //
  1495.                     if ('s' != pchToken[1])
  1496.                     {
  1497.                         dwSleep *= 1000L * 60;
  1498.                         szSleepUnit = szMinutes;
  1499.                     }
  1500.                     break;
  1501.  
  1502.                 case 'h':
  1503.                 case 'H':
  1504.                     dwSleep *= 1000L * 60 * 60;
  1505.                     szSleepUnit = szHours;
  1506.                     break;
  1507.             }
  1508.         }
  1509.  
  1510.         //
  1511.         //
  1512.         //
  1513.         AppSetWindowText(hwndStatus, szFormatSleeping, l, (LPSTR)szSleepUnit);
  1514.         MciAppDebugLog(szFormatSleeping, l, (LPSTR)szSleepUnit);
  1515.  
  1516.         if (!fYield)
  1517.             UpdateWindow(hwndStatus);
  1518.  
  1519.         //
  1520.         //  !!! broken !!!
  1521.         //
  1522.         //
  1523. #ifdef WIN32
  1524.         Sleep(dwSleep);
  1525. #else
  1526. {
  1527.         DWORD   dwStart;
  1528.  
  1529.         if (!fYield)
  1530.             AppHourGlass(TRUE);
  1531.  
  1532.         dwStart = timeGetTime();
  1533.         while ((timeGetTime() - dwStart) < dwSleep)
  1534.         {
  1535.             if (fYield)
  1536.             {
  1537.                 AppYield(hwnd, FALSE);
  1538.                 if (gfAbortExec)
  1539.                     break;
  1540.             }
  1541.             else
  1542.             {
  1543.                 if (GetAsyncKeyState(VK_ESCAPE) < 0)
  1544.                     break;
  1545.             }
  1546.         }
  1547.  
  1548.         if (!fYield)
  1549.             AppHourGlass(FALSE);
  1550. }
  1551. #endif
  1552.         
  1553.         AppSetWindowText(hwndStatus, szSleepComplete);
  1554.         MciAppDebugLog(szSleepDBComplete);
  1555.  
  1556.         if (!fYield)
  1557.             UpdateWindow(hwndStatus);
  1558.  
  1559.         return (TRUE);
  1560.     }
  1561.  
  1562.  
  1563. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1564. //
  1565. //  unrecognized command...
  1566. //
  1567. //
  1568. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1569.  
  1570.     MessageBeep((UINT)-1);
  1571.     AppSetWindowText(hwndStatus, szFormatError,
  1572.                      (LPSTR)pchCommand, (LPSTR)szErrorBadCmd);
  1573.     MciAppDebugLog(szFormatDBError, (LPSTR)pchCommand, (LPSTR)szErrorBadCmd);
  1574.  
  1575.     return (TRUE);
  1576. } // MciAppInternalCommand()
  1577.  
  1578.  
  1579. //--------------------------------------------------------------------------;
  1580. //
  1581. //  MCIERROR MciAppSingleStep
  1582. //
  1583. //  Description:
  1584. //      Executes one line from the script window.
  1585. //
  1586. //  Arguments:
  1587. //      HWND hwnd: Handle to main window.
  1588. //
  1589. //  Return (MCIERROR):
  1590. //      The return value is the MCIERROR return value from mciSendString.
  1591. //
  1592. //  History:
  1593. //       2/ 7/93    created.
  1594. //
  1595. //--------------------------------------------------------------------------;
  1596.  
  1597. MCIERROR FNGLOBAL MciAppSingleStep
  1598. (
  1599.     HWND            hwnd
  1600. )
  1601. {
  1602.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  1603.     HWND        hwndScript;
  1604.     int         nLine;
  1605.     int         nLineStart;
  1606.     int         nSelStart;
  1607.     int         nSelEnd;
  1608.     MCIERROR    mciError;
  1609.     BOOL        fDidOne;
  1610.  
  1611.     //
  1612.     //  initialize a bunch of stuff...
  1613.     //
  1614.     hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  1615.     mciError   = MMSYSERR_NOERROR;
  1616.     fDidOne    = FALSE;
  1617.     nLineStart = Edit_LineFromChar(hwndScript, -1);
  1618.     nLine      = nLineStart;
  1619.  
  1620.     //
  1621.     //  step through the script starting with the current line until we
  1622.     //  execute one non-comment/blank line...
  1623.     //
  1624.     for ( ; MciAppGetLine(hwndScript, nLine, ach, SIZEOF(ach)); nLine++)
  1625.     {
  1626.         //
  1627.         //  select the current line that is going to be executed....
  1628.         //
  1629.         nSelStart = Edit_LineIndex(hwndScript, nLine);
  1630.         nSelEnd   = Edit_LineIndex(hwndScript, nLine + 1);
  1631.         if (nSelEnd < nSelStart)
  1632.             nSelEnd = 0x7FFF;
  1633.         else if (nSelEnd > nSelStart)
  1634.             nSelEnd -= 1;
  1635.  
  1636.         Edit_SetSel(hwndScript, nSelStart, nSelEnd);
  1637.  
  1638.         //
  1639.         //  anything worth doing something with?
  1640.         //
  1641.         if (('\0' == ach[0]) || (';' == ach[0]))
  1642.             continue;
  1643.  
  1644.         //
  1645.         //  if first character is '!' then process rest of line as an
  1646.         //  internale MCI App command...
  1647.         //
  1648.         if ('!' == ach[0])
  1649.         {
  1650.             MciAppInternalCommand(hwnd, &ach[1], FALSE);
  1651.             continue;
  1652.         }
  1653.  
  1654.         //
  1655.         //  if we have actually executed a line, then break out... we do
  1656.         //  this so the above code will have selected the next line for
  1657.         //  single stepping.
  1658.         //
  1659.         if (fDidOne)
  1660.             break;
  1661.  
  1662.  
  1663.         //
  1664.         //  send the command on the current line to MCI via the string
  1665.         //  interface.
  1666.         //
  1667.         mciError = MciAppSendString(hwnd, ach);
  1668.         fDidOne  = TRUE;
  1669.     }
  1670.  
  1671.     SetFocus(hwndScript);
  1672.     return (mciError);
  1673. } // MciAppSingleStep()
  1674.  
  1675.  
  1676. //--------------------------------------------------------------------------;
  1677. //
  1678. //  MCIERROR MciAppExecute
  1679. //
  1680. //  Description:
  1681. //      Executes the MCI command which is currently selected in the script
  1682. //      window. If fSingleStep is TRUE, then only this one line will be
  1683. //      executed. Otherwise, every line from the currently selected line to
  1684. //      the last line in the script window will be executed sequentially.
  1685. //
  1686. //  Arguments:
  1687. //      HWND hwnd: Handle to main window.
  1688. //
  1689. //      BOOL fYield: TRUE if execution should yield between MCI commands.
  1690. //
  1691. //  Return (MCIERROR):
  1692. //      The return value is the last MCIERROR return value from executing.
  1693. //
  1694. //  History:
  1695. //       2/ 7/93    created.
  1696. //
  1697. //--------------------------------------------------------------------------;
  1698.  
  1699. MCIERROR FNGLOBAL MciAppExecute
  1700. (
  1701.     HWND            hwnd,
  1702.     BOOL            fYield
  1703. )
  1704. {
  1705.     static TCHAR    szFormatRuncount[]     = TEXT("%u");
  1706.  
  1707.     TCHAR       ach[APP_MAX_STRING_ERROR_CHARS];
  1708.     HWND        hwndScript;
  1709.     HWND        hwndRuncount;
  1710.     UINT        uRunCount;
  1711.     UINT        u;
  1712.     UINT        uLinesExecuted;
  1713.     int         n;
  1714.     int         nLine;
  1715.     int         nLineStart;
  1716.     int         nSelStart;
  1717.     int         nSelEnd;
  1718.     MCIERROR    mciError;
  1719.     BOOL        fIgnoreErrors;
  1720.  
  1721.  
  1722.     hwndScript   = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  1723.     hwndRuncount = GetDlgItem(hwnd, IDD_APP_EDIT_RUNCOUNT);
  1724.  
  1725.     uRunCount  = GetDlgItemInt(hwnd, IDD_APP_EDIT_RUNCOUNT, NULL, TRUE);
  1726.  
  1727.     uLinesExecuted = 0;
  1728.     mciError       = MMSYSERR_NOERROR;
  1729.     fIgnoreErrors  = FALSE;
  1730.  
  1731.     gfExecuting    = TRUE;
  1732.     gfAbortExec    = FALSE;
  1733.  
  1734.  
  1735.     //
  1736.     //  if we are yielding, then disable a bunch of controls...
  1737.     //
  1738.     //  if we are not yielding during then bring up an hour glass to show
  1739.     //  we be busy... don't bother with disabling controls--they can't
  1740.     //  be used
  1741.     //
  1742.     if (fYield)
  1743.     {
  1744.         static TCHAR    szButtonStop[]  = TEXT("&Stop");
  1745.  
  1746.         SetWindowText(GetDlgItem(hwnd, IDD_APP_BTN_STEP), szButtonStop);
  1747.  
  1748.         EnableWindow(GetDlgItem(hwnd, IDD_APP_BTN_GO),        FALSE);
  1749.         EnableWindow(GetDlgItem(hwnd, IDD_APP_BTN_RUN),       FALSE);
  1750.         EnableWindow(GetDlgItem(hwnd, IDD_APP_EDIT_RUNCOUNT), FALSE);
  1751.     }
  1752.     else
  1753.     {
  1754.         AppHourGlass(TRUE);
  1755.     }
  1756.  
  1757.  
  1758.     //
  1759.     //  go through every line in the script window from the currently
  1760.     //  selected line to the last line...
  1761.     //
  1762.     nLineStart = Edit_LineFromChar(hwndScript, -1);
  1763.     for (u = uRunCount; u; u--)
  1764.     {
  1765.         nLine = nLineStart;
  1766.         for ( ; MciAppGetLine(hwndScript, nLine, ach, SIZEOF(ach)); nLine++)
  1767.         {
  1768.             //
  1769.             //  select the current line that is going to be executed....
  1770.             //
  1771.             nSelStart = Edit_LineIndex(hwndScript, nLine);
  1772.             nSelEnd   = Edit_LineIndex(hwndScript, nLine + 1);
  1773.             if (nSelEnd < nSelStart)
  1774.                 nSelEnd = 0x7FFF;
  1775.             else if (nSelEnd > nSelStart)
  1776.                 nSelEnd -= 1;
  1777.  
  1778.             Edit_SetSel(hwndScript, nSelStart, nSelEnd);
  1779.  
  1780.  
  1781.             //
  1782.             //  check for abort...
  1783.             //
  1784.             if (gfAbortExec)
  1785.             {
  1786.                 n = AppMsgBoxId(hwnd, MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL,
  1787.                                 IDS_EXEC_ABORT);
  1788.                 if (IDYES == n)
  1789.                     goto MciApp_Execute_Exit;
  1790.  
  1791.                 gfAbortExec = FALSE;
  1792.             }
  1793.  
  1794.  
  1795.             //
  1796.             //  anything worth doing something with?
  1797.             //
  1798.             if (('\0' == ach[0]) || (';' == ach[0]))
  1799.                 continue;
  1800.  
  1801.             //
  1802.             //  if first character is '!' then process rest of line as an
  1803.             //  internale MCI App command...
  1804.             //
  1805.             if ('!' == ach[0])
  1806.             {
  1807.                 MciAppInternalCommand(hwnd, &ach[1], fYield);
  1808.                 continue;
  1809.             }
  1810.  
  1811.             //
  1812.             //  send the command on the current line to MCI via the string
  1813.             //  interface.
  1814.             //
  1815.             mciError = MciAppSendString(hwnd, ach);
  1816.             if ((MMSYSERR_NOERROR != mciError) && !fIgnoreErrors)
  1817.             {
  1818.                 n = DialogBox(ghinst, DLG_MCIERR, hwnd, (DLGPROC)MciAppErrorDlgProc);
  1819.                 switch (n)
  1820.                 {
  1821.                     case IDABORT:
  1822.                         goto MciApp_Execute_Exit;
  1823.  
  1824.                     case IDIGNORE:
  1825.                         fIgnoreErrors = TRUE;
  1826.                         break;
  1827.                 }
  1828.             }
  1829.  
  1830.             uLinesExecuted++;
  1831.  
  1832.             //
  1833.             //  yield like a good little app..
  1834.             //
  1835.             if (fYield)
  1836.                 AppYield(hwnd, FALSE);
  1837.             else
  1838.             {
  1839.                 UpdateWindow(GetDlgItem(hwnd, IDD_APP_TEXT_STATUS));
  1840.                 UpdateWindow(GetDlgItem(hwnd, IDD_APP_TEXT_OUTPUT));
  1841.             }
  1842.         }
  1843.  
  1844.         //
  1845.         //  SetDlgItemInt() won't update the field unless we yield
  1846.         //  so set window text instead... in case not yielding.
  1847.         //
  1848.         SetDlgItemInt(hwnd, IDD_APP_EDIT_RUNCOUNT, u, TRUE);
  1849.         if (fYield)
  1850.             AppYield(hwnd, FALSE);
  1851.         else
  1852.             UpdateWindow(GetDlgItem(hwnd, IDD_APP_EDIT_RUNCOUNT));
  1853.     }
  1854.  
  1855.  
  1856. MciApp_Execute_Exit:
  1857.  
  1858.     gfExecuting = FALSE;
  1859.     if (fYield)
  1860.     {
  1861.         static TCHAR    szButtonStep[]  = TEXT("&Step");
  1862.  
  1863.         SetWindowText(GetDlgItem(hwnd, IDD_APP_BTN_STEP), szButtonStep);
  1864.  
  1865.         EnableWindow(GetDlgItem(hwnd, IDD_APP_BTN_GO),        TRUE);
  1866.         EnableWindow(GetDlgItem(hwnd, IDD_APP_BTN_RUN),       TRUE);
  1867.         EnableWindow(GetDlgItem(hwnd, IDD_APP_EDIT_RUNCOUNT), TRUE);
  1868.     }
  1869.     else
  1870.     {
  1871.         AppHourGlass(FALSE);
  1872.     }
  1873.  
  1874.     SetDlgItemInt(hwnd, IDD_APP_EDIT_RUNCOUNT, uRunCount, TRUE);
  1875.     SetFocus(hwndScript);
  1876.  
  1877.     return (mciError);
  1878. } // MciAppExecute()
  1879.  
  1880.  
  1881. //--------------------------------------------------------------------------;
  1882. //
  1883. //  BOOL MciAppEnterLine
  1884. //
  1885. //  Description:
  1886. //      This function handles entering a new line into the script window.
  1887. //      This may involve executing the new line if Options.Edit Only is
  1888. //      not selected.
  1889. //
  1890. //  Arguments:
  1891. //      HWND hwnd: Handle to main window.
  1892. //
  1893. //      BOOL fEditOnly: TRUE if in data entry mode (won't single step the
  1894. //      current line before inserting CR/LF). FALSE if the current line
  1895. //      should be executed and a CR/LF inserted at the _END_ of the
  1896. //      current line.
  1897. //
  1898. //  Return (BOOL):
  1899. //      The return value is always TRUE.
  1900. //
  1901. //  History:
  1902. //       2/ 7/93    created.
  1903. //
  1904. //--------------------------------------------------------------------------;
  1905.  
  1906. BOOL FNGLOBAL MciAppEnterLine
  1907. (
  1908.     HWND            hwnd,
  1909.     BOOL            fEditOnly
  1910. )
  1911. {
  1912.     static TCHAR    szEOL[]     = TEXT("\r\n");
  1913.  
  1914.     HWND    hwndScript;
  1915.     int     n;
  1916.  
  1917.     hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  1918.  
  1919.     //
  1920.     //  if Options.Edit Only is checked or the user pressed Alt+Enter,
  1921.     //  then act like a simple edit control...
  1922.     //
  1923.     if (fEditOnly)
  1924.     {
  1925.         Edit_ReplaceSel(hwndScript, szEOL);
  1926.         return (TRUE);
  1927.     }
  1928.  
  1929.     //
  1930.     //  get current line (containing caret)--if there is a
  1931.     //  selection, the line number of the line containing the
  1932.     //  _beginning_ of the selection is retrieved.
  1933.     //
  1934.     SetFocus(hwndScript);
  1935.     n = Edit_LineFromChar(hwndScript, -1);
  1936.     MciAppSingleStep(hwnd);
  1937.     n = Edit_LineIndex(hwndScript, n);
  1938.     Edit_SetSel(hwndScript, n, n);
  1939.  
  1940.     //
  1941.     //  now force CR/LF at the _end_ of the current line
  1942.     //
  1943.     FORWARD_WM_KEYDOWN(hwndScript, VK_END, 1, 0, SendMessage);
  1944.     FORWARD_WM_KEYUP(hwndScript, VK_END, 1, 0, SendMessage);
  1945.     Edit_ReplaceSel(hwndScript, szEOL);
  1946.  
  1947.     return (TRUE);
  1948. } // MciAppEnterLine()
  1949.  
  1950.  
  1951. //==========================================================================;
  1952. //
  1953. //
  1954. //
  1955. //
  1956. //==========================================================================;
  1957.  
  1958. //--------------------------------------------------------------------------;
  1959. //
  1960. //  BOOL MciAppDispatchMessage
  1961. //
  1962. //  Description:
  1963. //
  1964. //
  1965. //  Arguments:
  1966. //
  1967. //
  1968. //  Return (BOOL):
  1969. //
  1970. //
  1971. //  History:
  1972. //       2/ 8/93    created.
  1973. //
  1974. //--------------------------------------------------------------------------;
  1975.  
  1976. BOOL FNGLOBAL MciAppDispatchMessage
  1977. (
  1978.     HWND            hwnd,
  1979.     PMSG            pmsg
  1980. )
  1981. {
  1982.     static HWND     hwndScript;
  1983.     static HACCEL   haccl;
  1984.  
  1985.     UINT        u;
  1986.  
  1987.     //
  1988.     //  if this is the first time through, cache some stuff...
  1989.     //
  1990.     if (NULL == hwndScript)
  1991.         hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  1992.  
  1993.     if (NULL == haccl)
  1994.         haccl = LoadAccelerators(ghinst, ACCEL_APP);
  1995.  
  1996.  
  1997.     //
  1998.     //  peek at the message being sent. if it is one of the special
  1999.     //  things for the script window, then deal with it...
  2000.     //
  2001.     //  !!! this is somewhat bogus !!!
  2002.     //
  2003.     if ((WM_KEYDOWN == pmsg->message) || (WM_SYSKEYDOWN == pmsg->message))
  2004.     {
  2005.         if (GetActiveWindow() != hwnd)
  2006.             goto MciApp_Dispatch_Continue;
  2007.  
  2008.         switch (pmsg->wParam)
  2009.         {
  2010.             case VK_RETURN:
  2011.                 if (GetFocus() != hwndScript)
  2012.                     break;
  2013.  
  2014.                 //
  2015.                 //  force a line to be 'executed' and stuff... if Alt+Enter
  2016.                 //  was used, then reverse the logic of 'Edit Only' by
  2017.                 //  setting uCode to 0 (from menu)
  2018.                 //
  2019.                 u = (GetKeyState(VK_MENU) < 0) ? 0 : 1;
  2020.                 FORWARD_WM_COMMAND(hwnd, IDOK, hwndScript, u, PostMessage);
  2021.                 return (TRUE);
  2022.  
  2023.             case VK_TAB:
  2024.                 if (WM_SYSKEYDOWN == pmsg->message)
  2025.                     break;
  2026.  
  2027.                 if (GetKeyState(VK_CONTROL) < 0)
  2028.                 {
  2029.                     if (GetFocus() == hwndScript)
  2030.                     {
  2031.                         SetFocus(GetDlgItem(hwnd, IDD_APP_BTN_STEP));
  2032.                         return (TRUE);
  2033.                     }
  2034.  
  2035.                     SetFocus(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT));
  2036.                     return (TRUE);
  2037.                 }
  2038.                 else if (GetFocus() == hwndScript)
  2039.                 {
  2040.                     static TCHAR    szTab[]     = TEXT("\t");
  2041.                     Edit_ReplaceSel(hwndScript, szTab);
  2042.                     return (TRUE);
  2043.                 }
  2044.                 break;
  2045.         }
  2046.     }
  2047.  
  2048.  
  2049. MciApp_Dispatch_Continue:
  2050.  
  2051.     //
  2052.     //  update the device list if it needs to be updated--also
  2053.     //  do the floating dialog box message thing...
  2054.     //
  2055.     if (NULL != ghwndDevices)
  2056.     {
  2057.         MciAppDeviceListUpdate(hwnd, ghwndDevices, FALSE);
  2058.  
  2059.         if (IsDialogMessage(ghwndDevices, pmsg))
  2060.             return (TRUE);
  2061.     }
  2062.  
  2063.  
  2064.     //
  2065.     //  take care of accelerators and dialog box style things...
  2066.     //
  2067.     if (TranslateAccelerator(hwnd, haccl, pmsg) ||
  2068.         IsDialogMessage(hwnd, pmsg))
  2069.     {
  2070.         return (TRUE);
  2071.     }
  2072.  
  2073.     TranslateMessage(pmsg);
  2074.     DispatchMessage(pmsg);
  2075.  
  2076.     return (TRUE);
  2077. } // MciAppDispatchMessage()
  2078.  
  2079.  
  2080. //==========================================================================;
  2081. //
  2082. //  Startup and shutdown code...
  2083. //
  2084. //
  2085. //==========================================================================;
  2086.  
  2087. TCHAR   gszKeyOptions[]     = TEXT("Options");
  2088. TCHAR   gszFormatOptions[]  = TEXT("%u");
  2089.  
  2090. TCHAR   gszKeyWindow[]      = TEXT("Window");
  2091. TCHAR   gszKeyFont[]        = TEXT("Font");
  2092.  
  2093.  
  2094. //--------------------------------------------------------------------------;
  2095. //
  2096. //  BOOL MciAppChooseFont
  2097. //
  2098. //  Description:
  2099. //      This function lets the user choose a new font for the script window.
  2100. //      After a new font is chosen, the font structure is stored to the
  2101. //      .ini file so it can be restored on the next run of this application.
  2102. //
  2103. //  Arguments:
  2104. //      HWND hwnd: Handle to main window.
  2105. //
  2106. //  Return (BOOL):
  2107. //      The return value is TRUE if a new font was chosen. It is FALSE if
  2108. //      the user canceled the operation.
  2109. //
  2110. //  History:
  2111. //       2/ 7/93    created.
  2112. //
  2113. //--------------------------------------------------------------------------;
  2114.  
  2115. BOOL FNGLOBAL MciAppChooseFont
  2116. (
  2117.     HWND            hwnd
  2118. )
  2119. {
  2120.     LOGFONT     lf;
  2121.     HWND        hwndScript;
  2122.     HFONT       hfont;
  2123.     HFONT       hfontNew;
  2124.  
  2125.     hwndScript = GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT);
  2126.  
  2127.     //
  2128.     //  get the current script font and pass it to the choose font dialog
  2129.     //
  2130.     hfont = GetWindowFont(hwndScript);
  2131.  
  2132.     hfontNew = AppChooseFont(hwnd, hfont, &lf);
  2133.     if (NULL == hfontNew)
  2134.         return (FALSE);
  2135.  
  2136.     //
  2137.     //  select the new font into the script window and delete the old one
  2138.     //
  2139.     SetWindowFont(hwndScript, hfontNew, TRUE);
  2140.     DeleteFont(hfont);
  2141.  
  2142.  
  2143.     //
  2144.     //  save the complete description of the chosen font so there can be
  2145.     //  no strangness in the font mapping next run. this is overkill, but
  2146.     //  it works...
  2147.     //
  2148.     AppProfileWriteBytes(gszKeyFont, (LPBYTE)&lf, sizeof(lf));
  2149.  
  2150.     return (TRUE);
  2151. } // MciAppChooseFont()
  2152.  
  2153.  
  2154. //--------------------------------------------------------------------------;
  2155. //
  2156. //  BOOL MciAppSettingsRestore
  2157. //
  2158. //  Description:
  2159. //      This function restores state information for the application. This
  2160. //      function is called just after the main window is created (it has
  2161. //      not been ShowWindow()'d). This function will generate the call
  2162. //      to ShowWindow before returning.
  2163. //
  2164. //  Arguments:
  2165. //      HWND hwnd: Handle to main window that has just been created but
  2166. //      not shown.
  2167. //
  2168. //      int nCmdShow: The state that the application window should show as.
  2169. //
  2170. //  Return (BOOL):
  2171. //      The return value is always TRUE.
  2172. //
  2173. //  History:
  2174. //       2/15/93    created.
  2175. //
  2176. //--------------------------------------------------------------------------;
  2177.  
  2178. BOOL FNLOCAL MciAppSettingsRestore
  2179. (
  2180.     HWND            hwnd,
  2181.     int             nCmdShow
  2182. )
  2183. {
  2184.     static TCHAR    szSecExtensions[]   = TEXT("Extensions");
  2185.     static TCHAR    szKeyMCI[]          = TEXT("mci");
  2186.     static TCHAR    szValAssocMCI[]     = TEXT("mciapp.exe ^.mci");
  2187.     static TCHAR    szKeyMCS[]          = TEXT("mcs");
  2188.     static TCHAR    szValAssocMCS[]     = TEXT("mciapp.exe ^.mcs");
  2189.  
  2190.     TCHAR           ach[APP_MAX_STRING_RC_CHARS];
  2191.     WINDOWPLACEMENT wp;
  2192.     HFONT           hfont;
  2193.     LOGFONT         lf;
  2194.     UINT            u;
  2195.     RECT            rc;
  2196.     RECT            rcWindow;
  2197.     POINT           pt;
  2198.     int             n;
  2199.     BOOL            f;
  2200.  
  2201.  
  2202.     //
  2203.     //  restore the previous Options state...
  2204.     //
  2205.     gfuAppOptions = GetProfileInt(gszAppSection, gszKeyOptions, gfuAppOptions);
  2206.  
  2207.  
  2208.     //
  2209.     //  we want to make sure that the association for .MCI and .MCS files is
  2210.     //  to run MCIAPP.EXE. this way any app that ShellExecute's a .MCI or
  2211.     //  .MCS file will run this app...
  2212.     //
  2213.     //  in WIN.INI:
  2214.     //
  2215.     //      [Extensions]
  2216.     //      mci = mciapp.exe ^.mci
  2217.     //      mcs = mciapp.exe ^.mcs
  2218.     //
  2219.     u = (UINT)GetProfileString(szSecExtensions, szKeyMCI, gszNull, ach, SIZEOF(ach));
  2220.     if ((0 == u) || lstrcmpi(ach, szValAssocMCI))
  2221.     {
  2222.         WriteProfileString(szSecExtensions, szKeyMCI, szValAssocMCI);
  2223.     }
  2224.  
  2225.     u = (UINT)GetProfileString(szSecExtensions, szKeyMCS, gszNull, ach, SIZEOF(ach));
  2226.     if ((0 == u) || lstrcmpi(ach, szValAssocMCS))
  2227.     {
  2228.         WriteProfileString(szSecExtensions, szKeyMCS, szValAssocMCS);
  2229.     }
  2230.  
  2231.     //
  2232.     //  restore the user's preferred font.
  2233.     //
  2234.     f = AppProfileReadBytes(gszKeyFont, (LPBYTE)&lf, sizeof(lf));
  2235.     if (f)
  2236.     {
  2237.         hfont = CreateFontIndirect(&lf);
  2238.         if (NULL != hfont)
  2239.         {
  2240.             SetWindowFont(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT), hfont, FALSE);
  2241.         }
  2242.     }
  2243.  
  2244.  
  2245.     //
  2246.     //  grab the stored window position and size from the .ini file...
  2247.     //  there must be four arguments stored or the entry is considered
  2248.     //  invalid.
  2249.     //
  2250.     f = AppProfileReadBytes(gszKeyWindow, (LPBYTE)&rcWindow, sizeof(rcWindow));
  2251.     if (f)
  2252.     {
  2253.         //
  2254.         //  to make sure the user can always get at the window, check to
  2255.         //  see if the midpoint of the caption is visible--if it is not,
  2256.         //  then default to the default position used when creating the
  2257.         //  window.
  2258.         //
  2259.         n = (rcWindow.right - rcWindow.left) / 2;
  2260.         pt.x = (n + rcWindow.left);
  2261.  
  2262.         n = GetSystemMetrics(SM_CYCAPTION) / 2 + GetSystemMetrics(SM_CXFRAME);
  2263.         pt.y = (n + rcWindow.top);
  2264.  
  2265.         GetWindowRect(GetDesktopWindow(), &rc);
  2266.         if (PtInRect(&rc, pt))
  2267.         {
  2268.             //
  2269.             //  fill out the window placement structure--default the
  2270.             //  maximized and minimized states to default placement by
  2271.             //  getting its current placement.
  2272.             //
  2273.             wp.length = sizeof(wp);
  2274.             GetWindowPlacement(hwnd, &wp);
  2275.  
  2276.             wp.showCmd          = nCmdShow;
  2277.             wp.rcNormalPosition = rcWindow;
  2278.  
  2279.             SetWindowPlacement(hwnd, &wp);
  2280.             return (TRUE);
  2281.         }
  2282.     }
  2283.  
  2284.     //
  2285.     //  show defaulted and succeed
  2286.     //
  2287.     ShowWindow(hwnd, nCmdShow);
  2288.     return (TRUE);
  2289. } // MciAppSettingsRestore()
  2290.  
  2291.  
  2292. //--------------------------------------------------------------------------;
  2293. //
  2294. //  BOOL MciAppSettingsSave
  2295. //
  2296. //  Description:
  2297. //      This function saves the current state information for the application.
  2298. //      It is called just before the main window is closed (destroyed); or
  2299. //      as Windows is exiting (query end session).
  2300. //
  2301. //      Note that this function should not destroy any resources--it can
  2302. //      be called at any time to save a snapshot of the application state.
  2303. //
  2304. //  Arguments:
  2305. //      HWND hwnd: Handle to main window that will be destroyed shortly.
  2306. //
  2307. //  Return (BOOL):
  2308. //      The return value is always TRUE.
  2309. //
  2310. //  History:
  2311. //       2/15/93    created.
  2312. //
  2313. //--------------------------------------------------------------------------;
  2314.  
  2315. BOOL FNGLOBAL MciAppSettingsSave
  2316. (
  2317.     HWND            hwnd
  2318. )
  2319. {
  2320.     TCHAR           ach[APP_MAX_STRING_RC_CHARS];
  2321.     WINDOWPLACEMENT wp;
  2322.     PRECT           prc;
  2323.     BOOL            f;
  2324.  
  2325.     //
  2326.     //  save the current option settings--note that we ALWAYS turn off the
  2327.     //  debug logging option so the app doesn't try to OutputDebugString
  2328.     //  unexpectedly during the next session...
  2329.     //
  2330.     gfuAppOptions &= ~APP_OPTF_DEBUGLOG;
  2331.     if (GetProfileInt(gszAppSection, gszKeyOptions, 0) != gfuAppOptions)
  2332.     {
  2333.         wsprintf(ach, gszFormatOptions, gfuAppOptions);
  2334.         WriteProfileString(gszAppSection, gszKeyOptions, ach);
  2335.     }
  2336.  
  2337.     //
  2338.     //  save the current window placement--only store the size and location
  2339.     //  of the restored window. maximized and minimized states should
  2340.     //  remain defaulted on the next invocation of this application.
  2341.     //
  2342.     wp.length = sizeof(wp);
  2343.     f = GetWindowPlacement(hwnd, &wp);
  2344.     if (f)
  2345.     {
  2346.         prc = &wp.rcNormalPosition;
  2347.  
  2348.         DPF(0, "WindowPlacement: show=%d, minX=%d, minY=%d, maxX=%d, maxY=%d",
  2349.              wp.showCmd, wp.ptMinPosition.x, wp.ptMinPosition.y,
  2350.              wp.ptMaxPosition.x, wp.ptMaxPosition.y);
  2351.  
  2352.         DPF(0, "                 normX=%d, normY=%d, normW=%d, normH=%d",
  2353.              prc->left, prc->top, prc->right, prc->bottom);
  2354.  
  2355.         //
  2356.         //  save the _bounding rectangle_ of the restored window state...
  2357.         //
  2358.         AppProfileWriteBytes(gszKeyWindow, (LPBYTE)prc, sizeof(*prc));
  2359.     }
  2360.  
  2361.  
  2362.     //
  2363.     //  succeed
  2364.     //
  2365.     return (TRUE);
  2366. } // MciAppSettingsSave()
  2367.  
  2368.  
  2369. //--------------------------------------------------------------------------;
  2370. //
  2371. //  BOOL MciAppShutdown
  2372. //
  2373. //  Description:
  2374. //      This function is called to gracefully shut down the application.
  2375. //      If the application should not be closed, a FALSE value is returned.
  2376. //      This function is called for WM_CLOSE and WM_QUERYENDSESSION
  2377. //      messages...
  2378. //
  2379. //  Arguments:
  2380. //      HWND hwnd: Handle to main window.
  2381. //
  2382. //      PTSTR pszFilePath: Pointer to current file path of script. If the
  2383. //      file needs to be saved, then this buffer will receive the new
  2384. //      file path if one is chosen.
  2385. //
  2386. //      PTSTR pszFilePath: Pointer to current file title of script. If the
  2387. //      file needs to be saved, then this buffer will receive the new
  2388. //      file title if one is chosen.
  2389. //
  2390. //  Return (BOOL):
  2391. //      Returns TRUE if the application can proceed with close. Returns
  2392. //      FALSE if the application should NOT be closed.
  2393. //
  2394. //  History:
  2395. //       2/ 9/93    created.
  2396. //
  2397. //--------------------------------------------------------------------------;
  2398.  
  2399. BOOL FNGLOBAL MciAppShutdown
  2400. (
  2401.     HWND            hwnd,
  2402.     PTSTR           pszFilePath,
  2403.     PTSTR           pszFileTitle
  2404. )
  2405. {
  2406.     int         n;
  2407.     UINT        u;
  2408.     BOOL        f;
  2409.  
  2410.     //
  2411.     //  if we are currently executing a script (Run or Go), things would
  2412.     //  get very messy if we tried to close the application. so disallow
  2413.     //  it!
  2414.     //
  2415.     //  !!! this is rude--bring up dialog with the problem statement !!!
  2416.     //
  2417.     if (gfExecuting)
  2418.     {
  2419.         MessageBeep((UINT)-1);
  2420.         return (FALSE);
  2421.     }
  2422.  
  2423.     //
  2424.     //  check if the script has been modified without saving. if the user
  2425.     //  cancels the operation, then we will NOT close the application.
  2426.     //
  2427.     f = MciAppFileSaveModified(hwnd, pszFilePath, pszFileTitle);
  2428.     if (!f)
  2429.         return (FALSE);
  2430.  
  2431.     //
  2432.     //  if devices are still open, ask user if we should close them down
  2433.     //  before exiting. the only reason we don't do this by default is
  2434.     //  for application cleanup testing in mmsystem... i suppose it is
  2435.     //  a nifty reminder for scripts that don't close devices also.
  2436.     //
  2437.     u = MciAppGetNumDevices(hwnd);
  2438.     if (0 != u)
  2439.     {
  2440.         n = AppMsgBoxId(hwnd, MB_YESNOCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL
  2441.                         | MB_SETFOREGROUND, IDS_WARN_OPEN_DEVICES, u);
  2442.         switch (n)
  2443.         {
  2444.             case IDYES:
  2445.                 MciAppCloseAllDevices(hwnd);
  2446.                 break;
  2447.  
  2448.             case IDNO:
  2449.                 break;
  2450.  
  2451.             case IDCANCEL:
  2452.                 return (FALSE);
  2453.         }
  2454.     }
  2455.  
  2456.  
  2457.     //
  2458.     //  save any settings that should be saved on app termination...
  2459.     //
  2460.     MciAppSettingsSave(hwnd);
  2461.  
  2462.     //
  2463.     //  allow closing of application...
  2464.     //
  2465.     return (TRUE);
  2466. } // MciAppShutdown()
  2467.  
  2468.  
  2469. //--------------------------------------------------------------------------;
  2470. //
  2471. //  BOOL MciAppInit
  2472. //
  2473. //  Description:
  2474. //
  2475. //
  2476. //  Arguments:
  2477. //
  2478. //
  2479. //  Return (BOOL):
  2480. //
  2481. //
  2482. //  History:
  2483. //       2/15/93    created.
  2484. //
  2485. //--------------------------------------------------------------------------;
  2486.  
  2487. BOOL FNGLOBAL MciAppInit
  2488. (
  2489.     HWND            hwnd,
  2490.     PTSTR           pszFilePath,
  2491.     PTSTR           pszFileTitle,
  2492.     LPTSTR          pszCmdLine,
  2493.     int             nCmdShow
  2494. )
  2495. {
  2496.     BOOL        f;
  2497.  
  2498.     //
  2499.     //
  2500.     //
  2501.     MciAppSettingsRestore(hwnd, nCmdShow);
  2502.  
  2503.     //
  2504.     //  strip the command line..
  2505.     //
  2506.     if (NULL != pszCmdLine)
  2507.     {
  2508.         while (('\0' != *pszCmdLine) && (' ' == *pszCmdLine))
  2509.             pszCmdLine++;
  2510.     }
  2511.  
  2512.     //
  2513.     //  if there is a command line, assume it is a filename for a script
  2514.     //  and try to open it. otherwise, just initialize the script window.
  2515.     //
  2516.     if ((NULL != pszCmdLine) && ('\0' != *pszCmdLine))
  2517.     {
  2518.         //
  2519.         //  attempt to open the specified file..
  2520.         //
  2521.         lstrcpy(pszFilePath, pszCmdLine);
  2522.         f = MciAppFileOpen(hwnd, pszFilePath, pszFileTitle);
  2523.         if (f)
  2524.         {
  2525.             AppTitle(hwnd, pszFileTitle);
  2526.             SetFocus(GetDlgItem(hwnd, IDD_APP_EDIT_SCRIPT));
  2527.         }
  2528.         else
  2529.         {
  2530.             //
  2531.             //  opening the command line file was untriumphant..
  2532.             //
  2533.             AppMsgBoxId(hwnd, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL,
  2534.                         IDS_ERROR_OPEN_FAILED, (LPSTR)pszFilePath);
  2535.  
  2536.  
  2537.             pszFilePath[0]  = '\0';
  2538.             pszFileTitle[0] = '\0';
  2539.             AppFileNew(hwnd, pszFilePath, pszFileTitle);
  2540.         }
  2541.     }
  2542.     else
  2543.     {
  2544.         AppFileNew(hwnd, pszFilePath, pszFileTitle);
  2545.     }
  2546.  
  2547.  
  2548.     //
  2549.     //
  2550.     //
  2551.     //
  2552.     MciAppDeviceList(hwnd, FALSE);
  2553.  
  2554.     return (TRUE);
  2555. } // MciAppInit()
  2556.  
  2557.  
  2558. //--------------------------------------------------------------------------;
  2559. //
  2560. //  BOOL MciAppExit
  2561. //
  2562. //  Description:
  2563. //
  2564. //
  2565. //  Arguments:
  2566. //
  2567. //
  2568. //  Return (BOOL):
  2569. //
  2570. //
  2571. //  History:
  2572. //       2/15/93    created.
  2573. //
  2574. //--------------------------------------------------------------------------;
  2575.  
  2576. BOOL FNGLOBAL MciAppExit
  2577. (
  2578.     void
  2579. )
  2580. {
  2581.     //
  2582.     //  clean up any resources and stuff we have allocated...
  2583.     //
  2584.  
  2585.     return (TRUE);
  2586. } // MciAppExit()
  2587.