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

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