home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tolkit45.zip / os2tk45 / samples / mm / caption / caption.c next >
C/C++ Source or Header  |  1999-05-11  |  144KB  |  2,986 lines

  1. /*----------------------------------------------------------------------------*/
  2. /* File Name   : Caption.c                                                    */
  3. /*                                                                            */
  4. /* Description : This file contains the C source code required for the        */
  5. /*               Caption Creation Utility program.                            */
  6. /*                                                                            */
  7. /* Concepts    : This sample program is part of MMPM/2 sample closed          */
  8. /*               captioning system.  This sample closed captioning system     */
  9. /*               is composed of three parts: Caption Creation Utility (this   */
  10. /*               (sample), Caption DLL, and Caption Sample Application.       */
  11. /*               The Caption Creation Utility (this program) creates a        */
  12. /*               "captioned" file. This is a text file with timing information*/
  13. /*               relating to it's associated audio file.  The Caption DLL     */
  14. /*               provides 3 API's that drive the display and management of a  */
  15. /*               "caption window" in a PM application.  The caption sample    */
  16. /*               illustrates how an application uses the 3 API's provided by  */
  17. /*               the caption DLL to take advantage of it's services.          */
  18. /*                                                                            */
  19. /*               This sample captioning system is provided to illustrate one  */
  20. /*               of the many ways that captioning may be implemented using    */
  21. /*               MMPM/2. As with all MMPM/2 samples, this may be used as it   */
  22. /*               is provided, or it may be modified in any way you prefer.    */
  23. /*               Please refer to the Application Programmers Reference for    */
  24. /*               more information on this sample captioning system.           */
  25. /*                                                                            */
  26. /* MMPM/2 API's :  List of all MMPM/2 API's that are used in                  */
  27. /*                 this module                                                */
  28. /*                                                                            */
  29. /*                 mciSendCommand    MCI_OPEN                                 */
  30. /*                                   MCI_PLAY                                 */
  31. /*                                   MCI_CLOSE                                */
  32. /*                                   MCI_SET                                  */
  33. /*                                   MCI_STOP                                 */
  34. /*                                   MCI_STATUS                               */
  35. /*                                   MCI_PAUSE                                */
  36. /*                                   MCI_LOAD                                 */
  37. /*                                   MCI_SET_POSITION_ADVISE                  */
  38. /*                                   MCI_ACQUIREDEVICE                        */
  39. /*                 mciGetErrorString                                          */
  40. /*                                                                            */
  41. /* Required                                                                   */
  42. /*    Files     :  caption.c        Source Code.                              */
  43. /*                 caption.h        Include file.                             */
  44. /*                 caption.dlg      Dialog definition.                        */
  45. /*                 caption.rc       Resources.                                */
  46. /*                 caption.ipf      Help text.                                */
  47. /*                 makefile         Make file.                                */
  48. /*                 caption.def      Linker definition file.                   */
  49. /*                 caption.ico      Program icon.                             */
  50. /*                 nextline.bmp     Next line pushbutton bitmap               */
  51. /*                 rewind.bmp       Rewind pushbutton bitmap                  */
  52. /*                 pause. BMP       Pause pushbutton bitmap                   */
  53. /*                 nextbusy.bmp     Next line pushbutton bitmap               */
  54. /*                 stop.bmp         Stop pushbutton bitmap                    */
  55. /*                 paused.bmp       Pause pushbutton bitmap                   */
  56. /*                 play0.bmp        Play pushbutton bitmap                    */
  57. /*                 play1.bmp        Play pushbutton bitmap                    */
  58. /*                 play2.bmp        Play pushbutton bitmap                    */
  59. /*                 play3.bmp        Play pushbutton bitmap                    */
  60. /*                 play4.bmp        Play pushbutton bitmap                    */
  61. /*                                                                            */
  62. /* Copyright (C) IBM 1993                                             */
  63. /*----------------------------------------------------------------------------*/
  64.  
  65. #define INCL_GPIPRIMITIVES        /*------------------------------------------*/
  66. #define INCL_GPIBITMAPS           /*                                          */
  67. #define INCL_GPILCIDS             /*                                          */
  68. #define INCL_WIN                  /*   Include appropriate sections           */
  69. #define INCL_DOSERRORS            /*                                          */
  70. #define INCL_WINHELP              /*                                          */
  71. #define INCL_DOSPROCESS           /*                                          */
  72. #define INCL_WINSTDSLIDER         /*                                          */
  73. #define INCL_OS2MM                /*   Required for MCI and MMIO headers      */
  74. #define INCL_SECONDARYWINDOW      /*                                          */
  75. #define INCL_GRAPHICBUTTON        /*------------------------------------------*/
  76.  
  77. #include <os2.h>                  /*-------- OS/2 header files ---------------*/
  78. #include <stdlib.h>               /*------------------------------------------*/
  79. #include <string.h>               /*          c header files                  */
  80. #include <stdio.h>                /*------------------------------------------*/
  81.  
  82. #include <sw.h>                   /*------------------------------------------*/
  83.                                   /*        MMPM/2 header files               */
  84. #include <os2me.h>                /*------------------------------------------*/
  85.                                   /*------------------------------------------*/
  86. #include "caption.h"              /*            Local header files            */
  87.                                   /*------------------------------------------*/
  88.  
  89.  
  90. /*---------------------- Function prototypes ---------------------------------*/
  91.  
  92. void             main           (void );
  93. MRESULT EXPENTRY MainWindowProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);
  94. MRESULT EXPENTRY TextWindowProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);
  95. MRESULT EXPENTRY FileFilterProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);
  96. MRESULT EXPENTRY ProductDlgProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  97. VOID    FormatFname     (CHAR szOutputName[], CHAR szInputName[] );
  98. ULONG   LoadAudioFile   (HWND hwnd, CHAR szFilename[] );
  99. ULONG   StartPlaying    (HWND hwnd );
  100. VOID    StopPlaying     (HWND hwnd );
  101. VOID    CloseAudioDevice(HWND hwnd );
  102. VOID    ShareAudioDevice(void );
  103. VOID    AudioError      (ULONG ulError );
  104. APIRET  LoadTextFile    (CHAR szFilename[] );
  105. VOID    PositionCaptions(SHORT sArmPos );
  106. VOID    DisplayTextLine (void );
  107. VOID    DisplayDosError (CHAR szTitle[], APIRET apiret );
  108. USHORT  SaveChanges     (ULONG flStyle );
  109. BOOL    CheckForTiming  (void );
  110. APIRET  SaveCaptionFile (CHAR szFilename[], SHORT sMenuItem );
  111. APIRET  WriteLine       (HFILE hfile, PSZ psz );
  112. VOID    ResizeTextWindow(LONG lNewDisplayLines );
  113. VOID    CreateTextBitmap(void );
  114. LONG    DisplaySaveasDlg(SHORT sMenuItem);
  115.  
  116. /*------------------------ Global Variables ----------------------------------*/
  117.  
  118. HAB                hab;            /*      Anchor block handle                */
  119.  
  120. MCI_OPEN_PARMS     mop;            /*-----------------------------------------*/
  121. MCI_GENERIC_PARMS  mgp;            /* Required for MMPM/2 calls.              */
  122. MCI_STATUS_PARMS   msp;            /*                                         */
  123. MCI_SET_PARMS      mspSet;         /*-----------------------------------------*/
  124.  
  125.                                    /*----------- Window handles --------------*/
  126.                                    /*                                         */
  127. HWND        hwndMainDlg;           /* Control window handle (dialog)          */
  128. HWND        hwndMainFrame;         /* Control window handle (frame)           */
  129. HWND        hwndMenu;              /* Menu bar in secondary frame window      */
  130. HWND        hwndText;              /* Frame window for scrolling text display */
  131. HWND        hwndHelp;              /* Help object window.                     */
  132. HWND        hwndVolume;            /* Volume control circular slider.         */
  133. HWND        hwndAudioSlider;       /* Audio slider in main dialog box.        */
  134. HWND        hwndProductInfo = 0;   /* Handle to the product info. dialog box  */
  135.                                    /*-----------------------------------------*/
  136.  
  137. RECTL       rclTextClient;         /* Dimensions of scrolling-text client area*/
  138. RECTL       rclMain;               /* Dimensions of main window               */
  139.  
  140. PVOID       pvText = NULL;         /* Pointer to text file image              */
  141. PVOID       pvLinedataTable;       /* Pointer to array of LINEDATA structures */
  142. USHORT      usLineCount;           /* Number of structures in Line Data table */
  143. USHORT      usDisplayLine;         /* Line displayed at the bottom of the txt */
  144. SHORT       sTotalVolume;          /* Total volume level slider can have      */
  145. SHORT       sCaptionArmRange;      /* Length of the caption slider control    */
  146.  
  147. int         iState    = ST_CLOSED; /* Initial state of the device             */
  148. CHAR        cEOF      = CHAR_EOF;
  149. ULONG       ulVolume  = 100;       /* Initial volume level                    */
  150.  
  151. FILEDLG     fdgAudio;
  152. CHAR        szErrorMsgTitle    [TITLE_LENGTH];  /* Title for Error message box*/
  153. CHAR        szAudioFile        [TITLE_LENGTH];  /* Store ".WAV" for open dlg  */
  154. CHAR        szCC_FILE[TITLE_LENGTH];            /* First line of CC files     */
  155. ULONG       ulAudioLength;                      /* Audio length in MM units   */
  156. SHORT       sAudioArmRange;                     /* Slider arm range in pels   */
  157.  
  158. FILEDLG     fdgText;
  159. CHAR        szTextOpen         [TITLE_LENGTH];  /* "Open Text File"           */
  160. CHAR        szCaptionOpen      [TITLE_LENGTH];  /* "Open Caption File"        */
  161. CHAR        szTextFile      [CCHMAXPATH] = "";  /* Text file full path        */
  162. CHAR        szCaptionFile   [CCHMAXPATH] = "";  /* Caption file full path     */
  163.  
  164. FILEDLG     fdgSaveAs;
  165. CHAR        szCapFileName      [TITLE_LENGTH];  /* Caption file name          */
  166. CHAR        szTextFileName     [TITLE_LENGTH];  /* Text file name             */
  167. CHAR        szAudioFileName    [TITLE_LENGTH];  /* Audio file name            */
  168. CHAR        szNoneFileName     [TITLE_LENGTH];  /* for "[none]" file name  */
  169.  
  170. USHORT      usFiledlgHelpRes;    /*   Help resource for latest file dialog    */
  171.  
  172. LONG        lTitleY;             /* System values which affect the size       */
  173.  
  174. HPS         hpsText;             /*-------------------------------------------*/
  175. HBITMAP     hbmText;             /*   Handles for text window backup bitmap   */
  176. HDC         hdcText;             /*-------------------------------------------*/
  177.  
  178. LONG        lScrollOffset = 0;   /*-------------------------------------------*/
  179. USHORT      usNextlineReq = 0;   /*       Variables used in scrolling         */
  180. USHORT      usNextline;          /*-------------------------------------------*/
  181.  
  182. LONG        lLineSpacing;        /*      Height of each line in pixels        */
  183. LONG        lLastLineY;          /*      Y coordinate of Bottom  line         */
  184. LONG        lDisplayLines;       /*      Number of lines in display           */
  185. LONG        lcyDialog;           /*      Dialog box cy value                  */
  186.  
  187. HELPINIT    helpinit;
  188. CHAR        szHelpTitle[TITLE_LENGTH];  /* "Caption Creation Utility Help"    */
  189. CHAR        szHelpLibrary[TITLE_LENGTH];/* Help library                       */
  190.  
  191. SHORT       sLatestPlayRequest;
  192. BOOL        bAcceptPlayRequests = TRUE;
  193.  
  194. USHORT      usPositionUP = 0;    /* Current valid Position advise serial nmbr */
  195.  
  196. BOOL        bAudioLoaded    = FALSE;  /* TRUE when audio file specified       */
  197. BOOL        bTextLoaded     = FALSE;  /* TRUE when text file specified        */
  198. BOOL        bCaptionsLoaded = FALSE;  /* TRUE when caption data avail         */
  199. BOOL        bUnsavedChanges = FALSE;  /* TRUE when changes have gone unsaved  */
  200.  
  201. BOOL        bMainActive     = FALSE;  /* TRUE when the main window is active  */
  202. BOOL        bAcquired       = FALSE;  /* TRUE when we have access to audio dev*/
  203.  
  204. SWP         swpMain;
  205.  
  206. HPOINTER    hptrWait, hptrArrow;/* Pointer handles for use during long waits. */
  207.  
  208.  
  209. /******************************************************************************
  210.  * Name         : main
  211.  *
  212.  * Description  : This function performs the necessary initializations and
  213.  *                setups that are required to show/run a dialog box as a
  214.  *                main window.  The message queue will be created, as well
  215.  *                the dialog box.  When program is terminated, the code will
  216.  *                destroy the help instance, message queue, and main window.
  217.  *
  218.  * Concepts     : None.
  219.  *
  220.  * MMPM/2 API's : mciSendString   MCI_GETDEVCAPS
  221.  *
  222.  * Parameters   : argc - Number of parameters passed into the program.
  223.  *                argv - Command line parameters.
  224.  *
  225.  * Return       : TRUE is returned to the operating system.
  226.  *
  227.  ******************************************************************************/
  228.  
  229. void main(  )
  230. {
  231.   HMQ     hmq;                        /* Handle to the message queue          */
  232.   QMSG    qmsg;                       /* Struc to hold a msg on the msg queue */
  233.   LONG    lX;                         /* Text window position, x coordinate   */
  234.   LONG    lY;                         /* Text window position, y coordinate   */
  235.   LONG    lWidth;                     /* Text window width                    */
  236.   LONG    lHeight;                    /* Text window height                   */
  237.   ULONG   ulBytesReq;                 /* Memory required for Line data table  */
  238.   CHAR    szError[80];                /* Buffer to hold help creation error   */
  239.   CHAR    szTitle[TITLE_LENGTH];      /* Buffer to hold Default size          */
  240.   BOOL    fHelpCreated = TRUE;        /* flag used for help creation          */
  241.   CHAR    szMainTitle [TITLE_LENGTH]; /* "Caption Creation Utility"           */
  242.   CHAR    szSave      [TITLE_LENGTH]; /* "Save as"                            */
  243.   CHAR    szSaveAsOpen[TITLE_LENGTH]; /* "Save caption file"                  */
  244.   CHAR    szAudioOpen [TITLE_LENGTH]; /* "Open Audio File"                    */
  245.   LONG    lmciSendStringRC;           /* return code from mciSendString       */
  246. /*----------------------- PM Initialization  ---------------------------------*/
  247.  
  248.   hab = WinInitialize ( 0 );
  249.   hmq = WinCreateMsgQueue ( hab, 50 );
  250.  
  251.   ulBytesReq = (ULONG)(MAX_TEXT_LINES*sizeof(LINEDATA));/* Allocate memory for*/
  252.   DosAllocMem ( &pvLinedataTable, ulBytesReq, fALLOC );/* the Line Data Table */
  253.  
  254.   hptrArrow = WinQuerySysPointer ( HWND_DESKTOP, SPTR_ARROW, FALSE );
  255.   hptrWait  = WinQuerySysPointer ( HWND_DESKTOP, SPTR_WAIT,  FALSE );
  256.  
  257. /*----------------------------------------------------------------------------*/
  258. /*  Load frequently-used strings from the program's resource file and save    */
  259. /*  them in static memory.  Strings which are seldom used will be loaded when */
  260. /*  needed in to local memory.                                                */
  261. /*----------------------------------------------------------------------------*/
  262.  
  263.   WinLoadString(hab, 0, STRID_OPEN_AUDIO,         TITLE_LENGTH,szAudioOpen    );
  264.   WinLoadString(hab, 0, STRID_OPEN_TEXT,          TITLE_LENGTH,szTextOpen     );
  265.   WinLoadString(hab, 0, STRID_OPEN_CAPTION,       TITLE_LENGTH,szCaptionOpen  );
  266.   WinLoadString(hab, 0, STRID_SAVEAS_TITLE,       TITLE_LENGTH,szSaveAsOpen   );
  267.   WinLoadString(hab, 0, STRID_SAVEAS_BUTTON,      TITLE_LENGTH,szSave         );
  268.   WinLoadString(hab, 0, STRID_HELP_TITLE,         TITLE_LENGTH,szHelpTitle    );
  269.   WinLoadString(hab, 0, STRID_DEFAULT_MAIN_TITLE, TITLE_LENGTH,szMainTitle    );
  270.   WinLoadString(hab, 0, STRID_HELP_LIBRARY_NAME,  TITLE_LENGTH,szHelpLibrary  );
  271.   WinLoadString(hab, 0, STRID_AUDIOFILE_EXTENTION,TITLE_LENGTH,szAudioFile    );
  272.   WinLoadString(hab, 0, STRID_FIRSTLINE_OF_CCFILE,TITLE_LENGTH,szCC_FILE      );
  273.   WinLoadString(hab, 0, STRID_ERROR_MESSAGE_TITLE,TITLE_LENGTH,szErrorMsgTitle);
  274.   WinLoadString(hab, 0, STRID_CAPTION_FILE_NAME,  TITLE_LENGTH,szCapFileName  );
  275.   WinLoadString(hab, 0, STRID_TEXT_FILE_NAME,     TITLE_LENGTH,szTextFileName );
  276.   WinLoadString(hab, 0, STRID_AUDIO_FILE_NAME,    TITLE_LENGTH,szAudioFileName);
  277.   WinLoadString(hab, 0, STRID_NONE_FILE_NAME,     TITLE_LENGTH,szNoneFileName );
  278.  
  279. /*----------- Create the backup bitmap for the text window -------------------*/
  280.  
  281.   lDisplayLines = CC_DEFAULT_LINES;
  282.   CreateTextBitmap();
  283.  
  284.  
  285.  
  286. /*------- Open the main window ( which is a Secondary Window ) ---------------*/
  287.  
  288.  
  289.   hwndMainFrame =
  290.       WinLoadSecondaryWindow(
  291.          HWND_DESKTOP,             /* Parent of the Secondary window.         */
  292.          (HWND) NULL,              /* Owner of the Secondary window.          */
  293.          (PFNWP) MainWindowProc,   /* Window procedure of Secondary window.   */
  294.          (HMODULE) NULL,           /* Dialog template is found in EXE resource*/
  295.          ID_MAIN_DLG,              /* Dialog template ID.                     */
  296.          (PVOID) NULL);            /* Creation Parameters for the dialog.     */
  297.  
  298.   hwndMenu = WinWindowFromID ( hwndMainFrame, FID_MENU );
  299.  
  300.   WinSetWindowText( hwndMainFrame, szMainTitle );      /* Default window title*/
  301.  
  302.   WinLoadString( hab, 0, STRID_DEFAULT_SIZE,  TITLE_LENGTH, szTitle );
  303.   WinInsertDefaultSize( hwndMainFrame, szTitle ); /*Add ~Default size to menu */
  304.  
  305.   hwndMainDlg = WinQuerySecondaryHWND( hwndMainFrame, QS_DIALOG );
  306.  
  307. /*-------- Find out the waveaudio on the system can play ---------------------*/
  308.  
  309.   lmciSendStringRC =
  310.       mciSendString( (PSZ)"capability waveaudio can play wait",
  311.                      (PSZ) NULL,
  312.                      CCHMAXPATH,
  313.                      (HWND) 0,
  314.                      0 );
  315.  
  316.   if (lmciSendStringRC != 0)          /* if can not play disable the Audio... */
  317.   {                                   /* menu item in the Open submenu        */
  318.      WinSendMsg( hwndMenu,
  319.                  MM_SETITEMATTR,
  320.                  MPFROM2SHORT( IDM_OPEN_AUDIO, TRUE ),
  321.                  MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED));
  322.   }
  323.  
  324. /*-------- Initialize the text window for scrolling captions -----------------*/
  325.   WinRegisterClass(
  326.      hab,
  327.      "TextWindow",
  328.      (PFNWP) TextWindowProc,
  329.      CS_SYNCPAINT | CS_SIZEREDRAW,
  330.      0 );
  331.   rclTextClient.xLeft   = 0;
  332.   rclTextClient.xRight  = CC_WIDTH;
  333.   rclTextClient.yBottom = 0;
  334.  
  335.   hwndText =
  336.       WinCreateWindow( (HWND)hwndMainDlg, "TextWindow", NULL, 0, 0, 0, 1,
  337.                        1, (HWND)hwndMainDlg, HWND_TOP, 111, NULL, NULL );
  338.  
  339.   WinQueryWindowRect( hwndMainDlg, &rclMain );
  340.  
  341.   lTitleY   = WinQuerySysValue ( HWND_DESKTOP, SV_CYTITLEBAR );
  342.   lWidth    = rclMain.xRight - 10;
  343.   lHeight   = ( 2 * lTitleY + rclTextClient.yTop );
  344.   lX        = 5;
  345.   lY        = ( rclMain.yTop - (rclMain.yTop / 5) ) ;
  346.  
  347.   lcyDialog = lHeight;
  348.  
  349.   WinSetWindowPos ( hwndText, 0, lX, lY, lWidth, lHeight,
  350.                                      SWP_SHOW | SWP_MOVE | SWP_SIZE );
  351.  
  352.   WinShowWindow( hwndMainFrame, TRUE );
  353.  
  354. /*------------- Initialize help for this application -------------------------*/
  355. /*                                                                            */
  356. /*   (1) Create a help instance.                                              */
  357. /*   (2) Associate the help instance with the secondary window                */
  358. /*                                                                            */
  359. /*----------------------------------------------------------------------------*/
  360.  
  361.   memset ( &helpinit, 0, sizeof(helpinit) );
  362.   helpinit.cb                 = sizeof(helpinit);
  363.   helpinit.fShowPanelId       = CMIC_HIDE_PANEL_ID;
  364.   helpinit.fShowPanelId       = (HMODULE) 0;
  365.   helpinit.pszHelpWindowTitle = (PSZ) szHelpTitle;
  366.   helpinit.pszHelpLibraryName = (PSZ) szHelpLibrary;
  367.   helpinit.phtHelpTable       = (PHELPTABLE) ( HELPTABLE_ID | 0xffff0000 );
  368.   helpinit.phtHelpTable       = (PVOID) ( HELPTABLE_ID | 0xffff0000 );
  369.  
  370.   hwndHelp =
  371.       WinCreateHelpInstance( hab, &helpinit ); /* (1) Create help instance    */
  372.  
  373.   if ( ! hwndHelp )
  374.      fHelpCreated = FALSE;
  375.   else
  376.   if (! WinAssociateHelpInstance( hwndHelp, hwndMainFrame )) /*(2) Assoc. help*/
  377.      fHelpCreated = FALSE;
  378.  
  379.   if ( ! fHelpCreated )
  380.   {
  381.      WinLoadString ( hab, (HMODULE)NULL, STRID_HELP_CREATION_FAILED,
  382.                                                    ERROR_LENGTH, szError );
  383.      WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szErrorMsgTitle,
  384.                                        0, MB_OK | MB_ERROR | MB_MOVEABLE );
  385.   }
  386.  
  387.  
  388. /*----------- Initialize the File Dialog data structures ---------------------*/
  389.  
  390.    memset ( &fdgAudio, 0, sizeof(fdgAudio) );      /*-------------------------*/
  391.    fdgAudio.cbSize   = sizeof(fdgAudio);           /*                         */
  392.    fdgAudio.fl = FDS_HELPBUTTON | FDS_CENTER       /*                         */
  393.                               | FDS_OPEN_DIALOG;   /*   Audio file            */
  394.    fdgAudio.pszTitle = (PSZ) szAudioOpen;          /*                         */
  395.    fdgAudio.pfnDlgProc = (PFNWP) FileFilterProc;   /*                         */
  396.                                                    /*-------------------------*/
  397.  
  398.    memset ( &fdgText, 0, sizeof(fdgText) );        /*-------------------------*/
  399.    fdgText.cbSize   = sizeof(fdgText);             /*                         */
  400.    fdgText.fl = FDS_HELPBUTTON | FDS_CENTER        /*                         */
  401.                               | FDS_OPEN_DIALOG;   /*    Text file            */
  402.    fdgText.pfnDlgProc = (PFNWP) FileFilterProc;    /*                         */
  403.                                                    /*                         */
  404.                                                    /*-------------------------*/
  405.  
  406.    memset ( &fdgSaveAs, 0, sizeof(fdgSaveAs) );    /*-------------------------*/
  407.    fdgSaveAs.cbSize   = sizeof(fdgSaveAs);         /*                         */
  408.    fdgSaveAs.fl = FDS_HELPBUTTON | FDS_CENTER      /*                         */
  409.                               | FDS_OPEN_DIALOG;   /*   Saveas file           */
  410.    fdgSaveAs.pszTitle = (PSZ) szSaveAsOpen;        /*                         */
  411.    fdgSaveAs.pfnDlgProc = (PFNWP) FileFilterProc;  /*                         */
  412.    fdgSaveAs.pszOKButton = (PSZ) szSave;           /*-------------------------*/
  413.  
  414.  
  415. /*----------- Initialize the Open parameter data structure--------------------*/
  416.  
  417.    mop.usDeviceID = (USHORT) NULL;
  418.  
  419. /*------------------------- Message Loop  ------------------------------------*/
  420.  
  421.   while( WinGetMsg( hab, &qmsg, 0, 0, 0 ) )
  422.     WinDispatchMsg( hab, &qmsg );
  423.  
  424.  
  425. /*---------------------------- Wrapup ----------------------------------------*/
  426.  
  427.   WinDestroyHelpInstance   ( hwndHelp );     /*-------------------------------*/
  428.   WinDestroySecondaryWindow( hwndMainFrame );/*Destroy windows we have created*/
  429.   WinDestroyWindow         ( hwndText );     /*-------------------------------*/
  430.  
  431.   GpiDestroyPS             ( hpsText );   /*----------------------------------*/
  432.   DevCloseDC               ( hdcText );   /*Get rid of text wndw backup bitmap*/
  433.   GpiDeleteBitmap          ( hbmText );   /*----------------------------------*/
  434.  
  435.   DosFreeMem               ( pvLinedataTable);  /* Free Line Data Tbl memory  */
  436.  
  437.   WinDestroyMsgQueue       ( hmq );             /* Destroy msg queue          */
  438.   WinTerminate             ( hab );
  439. }
  440.  
  441. /******************************************************************************
  442.  * Name         : MainWindowProc
  443.  *
  444.  * Description  : This function controls the main dialog box.  It will handle
  445.  *                received messages such as pushbutton notifications, timing
  446.  *                events, etc.
  447.  *
  448.  * Concepts     : - How to participate in MMPM/2 device sharing scheme.
  449.  *                - How to handle notification messages.
  450.  *
  451.  * MMPM/2 API's : mciSendCommand
  452.  *                   MCI_STATUS
  453.  *                   MCI_PAUSE
  454.  *                   MCI_RESUME
  455.  *                   MCI_SET
  456.  *
  457.  * Parameters   : hwnd - Handle for the Main dialog box.
  458.  *                msg  - Message received by the dialog box.
  459.  *                mp1  - Parameter 1 for the just received message.
  460.  *                mp2  - Parameter 2 for the just received message.
  461.  *
  462.  * Return       :
  463.  *
  464.  ******************************************************************************/
  465. MRESULT EXPENTRY MainWindowProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  466. {
  467.   ULONG         ulError;                /* for return value                   */
  468.   USHORT        usNotifyCode;           /* for notification code              */
  469.   USHORT        usUserParm;             /* for user parameter                 */
  470.   USHORT        usCommandMessage;       /* for command message                */
  471.   APIRET        apiret;                 /* for api return code                */
  472.   PLINEDATA     pld;                    /* Local pointer to the Line Data Tb  */
  473.   ULONG         ulTime;                 /* Media position in mm units         */
  474.   PSZ           psz, pszSlash;          /* pointers for temporary storage     */
  475.   PSZ           pszFileName;            /* for file name                      */
  476.   USHORT        usTestLine;             /* for text line in the text window   */
  477.   PSWP          pswp;
  478.   SHORT         sArmPosition;           /* Updated slider arm position        */
  479.   SHORT         sControlID;             /* Control ID for WM_CONTROL messages */
  480.   SHORT         sCommandID;             /* Command ID for WM_COMMAND messages */
  481.   PCHAR         pcTextFile;             /* buffer for window title text       */
  482.   CHAR          szBuffer[CCHMAXPATH];   /* temporary buffer to store file name*/
  483.   MRESULT       mresult;                /* for return result                  */
  484.  
  485. /*----------------------------------------------------------------------------*/
  486.  
  487.   switch( msg )
  488.   {
  489.      /*---------------- Dialog initialization --------------------------------*/
  490.      /*                                                                       */
  491.      /* (1) Determine a number of window handles for dialog controls.  This   */
  492.      /*     will save time ( and code lines ) later.                          */
  493.      /* (2) Initialize the text in the files group box                        */
  494.      /* (3) Set the scale and position of the Volume control.                 */
  495.      /* (4) Set the animation rate for the Play and Start Timing pushbuttons. */
  496.      /*-----------------------------------------------------------------------*/
  497.  
  498.      case WM_INITDLG:
  499.         hwndAudioSlider = WinWindowFromID( hwnd, ID_AUDIO_SLIDER ); /* (1)    */
  500.         hwndVolume      = WinWindowFromID( hwnd, ID_VOLUME       );
  501.  
  502.         strcpy(szBuffer, szTextFileName);                             /* (2)  */
  503.         strcat(szBuffer, szNoneFileName);
  504.         WinSetWindowText( WinWindowFromID( hwnd, ID_TEXTTXT), szBuffer );
  505.  
  506.         strcpy(szBuffer, szAudioFileName);
  507.         strcat(szBuffer, szNoneFileName);
  508.         WinSetWindowText( WinWindowFromID( hwnd, ID_AUDIOTXT), szBuffer );
  509.  
  510.         strcpy(szBuffer, szCapFileName);
  511.         strcat(szBuffer, szNoneFileName);
  512.         WinSetWindowText( WinWindowFromID( hwnd, ID_CAPTIONTXT), szBuffer );
  513.  
  514.         WinSendMsg( hwndVolume, SLM_SETTICKSIZE,                      /* (3)  */
  515.                     (MPARAM)MPFROM2SHORT (0, 3),
  516.                     (MPARAM)0 );
  517.  
  518.         WinSendMsg( hwndVolume, SLM_SETSCALETEXT,
  519.                     (MPARAM)0, (MPARAM) "0%" );
  520.  
  521.         WinSendMsg( hwndVolume, SLM_SETTICKSIZE,
  522.                     (MPARAM)MPFROM2SHORT (25, 3), (MPARAM)0 );
  523.  
  524.         WinSendMsg( hwndVolume, SLM_SETTICKSIZE,
  525.                     (MPARAM)MPFROM2SHORT (50, 3), (MPARAM)0 );
  526.  
  527.         WinSendMsg( hwndVolume, SLM_SETSCALETEXT,
  528.                     (MPARAM)50, (MPARAM) "50%" );
  529.  
  530.         WinSendMsg( hwndVolume, SLM_SETTICKSIZE,
  531.                     (MPARAM)MPFROM2SHORT (75, 3), (MPARAM)0 );
  532.  
  533.         WinSendMsg( hwndVolume, SLM_SETTICKSIZE,
  534.                     (MPARAM)MPFROM2SHORT (99, 3), (MPARAM)0 );
  535.  
  536.         WinSendMsg( hwndVolume, SLM_SETSCALETEXT,
  537.                     (MPARAM)99, (MPARAM) "100%" );
  538.  
  539.         mresult =
  540.           WinSendMsg( hwndVolume,
  541.                       SLM_QUERYSLIDERINFO,
  542.                       MPFROM2SHORT( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  543.                       0 );
  544.         sTotalVolume = SHORT2FROMMP( (MPARAM) mresult );
  545.  
  546.         WinSendMsg(
  547.               hwndVolume,
  548.               SLM_SETSLIDERINFO,
  549.               MPFROM2SHORT( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  550.               MPFROMSHORT( sTotalVolume - 1 ));
  551.  
  552.         WinSendDlgItemMsg( hwnd, ID_SET_TIMING, GBM_SETANIMATIONRATE,  /* (4) */
  553.                                                 MPFROMLONG(100), 0 );
  554.         WinSendDlgItemMsg( hwnd, ID_PLAY, GBM_SETANIMATIONRATE,
  555.                                           MPFROMLONG(100), 0 );
  556.  
  557.         break;
  558.  
  559.      /*---------------------- Activate message -------------------------------*/
  560.      /*                                                                       */
  561.      /*   Keep up with the active status of the Main window.                  */
  562.      /*   Whenever the main window is activated, we must:                     */
  563.      /*                                                                       */
  564.      /*  (1) See if we need to regain control of the audio device.            */
  565.      /*                                                                       */
  566.      /*-----------------------------------------------------------------------*/
  567.  
  568.      case WM_ACTIVATE:
  569.         if ( SHORT1FROMMP ( mp1 ) )
  570.         {
  571.            bMainActive = TRUE;
  572.            ShareAudioDevice();
  573.         }
  574.         else
  575.            bMainActive = FALSE;
  576.  
  577.         break;
  578.  
  579.      case WM_COMMAND:
  580.         sCommandID = SHORT1FROMMP(mp1);
  581.  
  582.         /*--------------------------------------------------------------------*/
  583.         /*  The accelerator table will give us WM_COMMAND messages for        */
  584.         /*  pushbuttons, even if the buttons are disabled.  If this message   */
  585.         /*  originated from the accelerator table, make sure it is NOT coming */
  586.         /*  from a disabled pushbutton.                                       */
  587.         /*--------------------------------------------------------------------*/
  588.  
  589.         if ( ( SHORT1FROMMP(mp2) == CMDSRC_ACCELERATOR ) &&
  590.              ( ( sCommandID == ID_SET_TIMING ) ||
  591.                ( sCommandID == ID_PLAY       ) ||
  592.                ( sCommandID == ID_NEXTLINE   ) ||
  593.                ( sCommandID == ID_REWIND     ) ||
  594.                ( sCommandID == ID_PAUSE      ) ||
  595.                ( sCommandID == ID_STOP       ) ) )
  596.            if ( ! WinIsWindowEnabled(
  597.                      WinWindowFromID( hwnd, (ULONG) sCommandID )))
  598.            {
  599.               WinAlarm( HWND_DESKTOP, WA_WARNING );/* Disabled pushbutton give*/
  600.               break;                               /* a warning beep and exit.*/
  601.            }
  602.  
  603.         switch ( sCommandID )
  604.         {
  605.            /*---------------- Start Timing pushbutton ------------------------*/
  606.            /*                                                                 */
  607.            /* (1) Check to see if there is already a Play or Start Timing     */
  608.            /*     operation in progress.  If so, chastise the user and exit.  */
  609.            /*                                                                 */
  610.            /* (2) Set switches to indicate a Start Timing operation is in     */
  611.            /*     progress and initialize queued line count to zero.          */
  612.            /*                                                                 */
  613.            /* (3) Start playing the audio.                                    */
  614.            /*-----------------------------------------------------------------*/
  615.  
  616.            case ID_SET_TIMING:
  617.               if ( ! bAcceptPlayRequests )              /* (1) Alredy playing?*/
  618.                  WinAlarm ( HWND_DESKTOP, WA_WARNING );
  619.               else
  620.               {
  621.                  bAcceptPlayRequests = FALSE;        /* (2) Timing switch set */
  622.                  sLatestPlayRequest  = ID_SET_TIMING;
  623.                  usNextlineReq = 0;
  624.                  WinSetPointer ( HWND_DESKTOP, hptrWait );
  625.                  ulError = StartPlaying( hwnd );     /* (3) Start playing     */
  626.                  WinSetPointer ( HWND_DESKTOP, hptrArrow );
  627.                  if ( ulError ) AudioError ( ulError );
  628.               }
  629.               break;
  630.  
  631.  
  632.            /*------------------- Play pushbutton -----------------------------*/
  633.            /*                                                                 */
  634.            /* (1) Check to see if there is already a Play or Start Timing n   */
  635.            /*     operation in progress.  If so, chastise the user and exit.  */
  636.            /*                                                                 */
  637.            /* (2) Set switches to indicate a Play operation is in progress    */
  638.            /*     and initialize queued line count to zero.                   */
  639.            /*                                                                 */
  640.            /* (3) Start playing the audio.                                    */
  641.            /*-----------------------------------------------------------------*/
  642.  
  643.            case ID_PLAY:
  644.               if ( ! bAcceptPlayRequests )              /* (1) Alredy playing?*/
  645.                  WinAlarm ( HWND_DESKTOP, WA_WARNING );
  646.               else
  647.               {
  648.                  bAcceptPlayRequests = FALSE;        /* (2) Play switch setup */
  649.                  sLatestPlayRequest = ID_PLAY;
  650.                  usNextlineReq = 0;
  651.                  WinSetPointer ( HWND_DESKTOP, hptrWait );
  652.                  ulError = StartPlaying( hwnd );     /* (3) Start playing     */
  653.                  WinSetPointer ( HWND_DESKTOP, hptrArrow );
  654.                  if ( ulError ) AudioError ( ulError );
  655.               }
  656.               break;
  657.  
  658.  
  659.            /*--------------- Advance Line pushbutton -------------------------*/
  660.            /*                                                                 */
  661.            /* (1) Check variable usNextline for the index of the line to be   */
  662.            /*     associated with this button push.                           */
  663.            /*                                                                 */
  664.            /* (2) If we have not reached the end of the text, then ask for the*/
  665.            /*     current audio position ( in MM units ) and place it in the  */
  666.            /*     LINEDATA entry for this text line.                          */
  667.            /*                                                                 */
  668.            /* (3) Next we check variable usNextlineReq. This gives us the     */
  669.            /*     number of lines queued up to be scrolled into the text wnd. */
  670.            /*                                                                 */
  671.            /* (4) If this is the only line waiting, highlight the Advance Line*/
  672.            /*     control and post a message to the text window, directing it */
  673.            /*     to start a scroll operation; but if there are other lines   */
  674.            /*     queued up to be scrolled, exit after incrementing           */
  675.            /*     usNextlineReq.                                              */
  676.            /*-----------------------------------------------------------------*/
  677.  
  678.            case ID_NEXTLINE:
  679.               if ( usNextline < usLineCount )      /* (1) Check usNextline    */
  680.               {
  681.                  msp.hwndCallback = (HWND) NULL;    /* (2) Get audio position..*/
  682.                  msp.ulItem     = MCI_STATUS_POSITION;
  683.                  ulError = mciSendCommand ( mop.usDeviceID,
  684.                                             MCI_STATUS,
  685.                                             MCI_WAIT | MCI_STATUS_ITEM,
  686.                                             (PVOID) &msp,
  687.                                             (USHORT)  UP_STATUS );
  688.                  if ( !ulError )
  689.                     AudioError ( ulError );
  690.                  else
  691.                  {
  692.                     pld = (PLINEDATA) pvLinedataTable + usNextline;
  693.                     pld->ulTime = msp.ulReturn;
  694.                     bUnsavedChanges = TRUE;        /*....and mark in LINEDATA */
  695.                     usNextline++;
  696.                  }
  697.                  usNextlineReq++;
  698.                  if ( usNextlineReq == 1 )      /* (3) Check for queued lines */
  699.                  {
  700.                     WinSendDlgItemMsg(                        /*--------------*/
  701.                            hwnd, ID_NEXTLINE,                 /*              */
  702.                            GBM_SETBITMAPINDEX,                /* (4) Hilite   */
  703.                            MPFROMSHORT(GB_CURRENTSTATE),      /* adv line and */
  704.                            MPFROMSHORT(1) );                  /* post message */
  705.                     WinPostMsg( hwndText, UM_NEXTLINE, 0, 0 );/*--------------*/
  706.                  }
  707.               }
  708.               break;
  709.  
  710.            case ID_PAUSE:
  711.               switch ( iState )
  712.               {
  713.                  /*------------ Pause the current operation ------------------*/
  714.                  /*                                                           */
  715.                  /* (1) Pause the audio play.                                 */
  716.                  /* (2) Update internal status.                               */
  717.                  /* (3) Highlight the PAUSE graphic pushbutton.               */
  718.                  /* (4) Enable the HELP submenu.                              */
  719.                  /* (5) Freeze the animated graphic pushbutton for the latest */
  720.                  /*     operation ( either Start timing or Play ).            */
  721.                  /* (6) If the latest operation was Start timing, disable the */
  722.                  /*     Advance Line pushbutton.                              */
  723.                  /*-----------------------------------------------------------*/
  724.  
  725.                  case ST_PLAYING:
  726.                     mgp.hwndCallback = (HWND) NULL;    /*---------------------*/
  727.                     mciSendCommand ( mop.usDeviceID,   /*  (1) Pause audio    */
  728.                                      MCI_PAUSE,        /*---------------------*/
  729.                                      MCI_WAIT,
  730.                                      (PVOID) &mgp,
  731.                                      (USHORT) UP_PAUSE );
  732.  
  733.                     iState = ST_PAUSED;                  /* (2) Update state  */
  734.  
  735.                     WinSendDlgItemMsg ( hwnd, ID_PAUSE,  /* (3) Highlite pause*/
  736.                                         GBM_SETBITMAPINDEX,
  737.                                         MPFROMSHORT(GB_CURRENTSTATE),
  738.                                         MPFROMSHORT(1) );
  739.  
  740.                     if (sLatestPlayRequest==ID_SET_TIMING)/*(4) Freeze anim.  */
  741.                     {                                     /*(5) Dsabl Adv Line*/
  742.                        WinEnableWindow ( WinWindowFromID( hwnd, ID_NEXTLINE ),
  743.                                          FALSE );
  744.                        WinSendDlgItemMsg ( hwndMainDlg, ID_SET_TIMING,
  745.                                            GBM_ANIMATE,
  746.                                            MPFROMSHORT((SHORT)FALSE),
  747.                                            MPFROMSHORT((SHORT)FALSE) );
  748.                     }
  749.                     else
  750.                        WinSendDlgItemMsg ( hwndMainDlg, ID_PLAY, GBM_ANIMATE,
  751.                                            MPFROMSHORT((SHORT)FALSE),
  752.                                            MPFROMSHORT((SHORT)FALSE) );
  753.                     break;
  754.  
  755.  
  756.                  /*-------------- Resume the current operation ---------------*/
  757.                  /*                                                           */
  758.                  /* (1) Resume the audio play.                                */
  759.                  /* (2) Update internal status.                               */
  760.                  /* (3) Unhighlight the PAUSE graphic pushbutton.             */
  761.                  /* (4) Disable the HELP submenu.                             */
  762.                  /* (5) Resume animation of the graphic pushbutton for the    */
  763.                  /*     latest operation ( either Start timing or Play ).     */
  764.                  /* (6) If the latest operation was Start timing, enable the  */
  765.                  /*     Advance Line pushbutton.                              */
  766.                  /*-----------------------------------------------------------*/
  767.  
  768.                  case ST_PAUSED:
  769.                     mgp.hwndCallback = (HWND) NULL;  /*-----------------------*/
  770.                     mciSendCommand ( mop.usDeviceID, /*  (1) Resume audio     */
  771.                                      MCI_RESUME,     /*-----------------------*/
  772.                                      MCI_WAIT,
  773.                                      (PVOID) &mgp,
  774.                                      (USHORT) UP_RESUME );
  775.  
  776.                     iState = ST_PLAYING;                 /* (2) Update state  */
  777.  
  778.                     WinSendDlgItemMsg ( hwnd, ID_PAUSE,  /* (3) Unhilite pause*/
  779.                                         GBM_SETBITMAPINDEX,
  780.                                         MPFROMSHORT(GB_CURRENTSTATE),
  781.                                         MPFROMSHORT(0) );
  782.  
  783.                     if (sLatestPlayRequest==ID_SET_TIMING)/*(4) Animate       */
  784.                     {                                     /*(5) Enabl Adv Line*/
  785.                        WinEnableWindow ( WinWindowFromID ( hwnd, ID_NEXTLINE ),
  786.                                          TRUE );
  787.                        WinSendDlgItemMsg ( hwndMainDlg, ID_SET_TIMING,
  788.                                            GBM_ANIMATE,
  789.                                            MPFROMSHORT((SHORT)TRUE),
  790.                                            MPFROMSHORT((SHORT)FALSE) );
  791.                     }
  792.                     else
  793.                        WinSendDlgItemMsg ( hwndMainDlg, ID_PLAY, GBM_ANIMATE,
  794.                                            MPFROMSHORT((SHORT)TRUE),
  795.                                            MPFROMSHORT((SHORT)FALSE) );
  796.                     break;
  797.               }
  798.               break;
  799.                                                      /*-----------------------*/
  800.                                                      /*        Stop           */
  801.            case ID_STOP:                             /*-----------------------*/
  802.               StopPlaying( hwnd );
  803.               break;                                 /*-----------------------*/
  804.                                                      /*        Rewind         */
  805.                                                      /*-----------------------*/
  806.            case ID_REWIND:
  807.               StopPlaying( hwnd );
  808.               WinSendMsg(hwndAudioSlider, SLM_SETSLIDERINFO,
  809.                          MPFROM2SHORT( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  810.                          MPFROMSHORT( 0 ) );
  811.               PositionCaptions ( 0 );
  812.               break;
  813.  
  814.  
  815.            /*---------------- Open Audio... menu item ------------------------*/
  816.            /*                                                                 */
  817.            /*  (1) Set the appropriate help resource for this operation.      */
  818.            /*  (2) Reformat the latest audio file name as:  x:\pathname\*.ext */
  819.            /*  (3) Request the user to select a file                          */
  820.            /*  (4) If the user selected a file, try to open it.               */
  821.            /*-----------------------------------------------------------------*/
  822.  
  823.            case IDM_OPEN_AUDIO:
  824.               usFiledlgHelpRes = PANEL_FILEDLG_AUDIO;     /*(1) Help resource */
  825.  
  826.               FormatFname( fdgAudio.szFullFile, szAudioFile );/*(2)Format name*/
  827.  
  828.               if (WinFileDlg(HWND_DESKTOP, hwnd, &fdgAudio))/*(3) Request file*/
  829.                  if ( fdgAudio.lReturn == DID_OK )
  830.                  {
  831.                     if (iState == ST_PLAYING ) StopPlaying( hwnd );
  832.                     WinSetPointer(HWND_DESKTOP, hptrWait);/*(4) Try opening it*/
  833.                     ulError = LoadAudioFile ( hwnd, fdgAudio.szFullFile );
  834.                     WinSetPointer ( HWND_DESKTOP, hptrArrow );
  835.                     if ( ulError) AudioError ( ulError );
  836.                  }
  837.               break;
  838.  
  839.  
  840.            /*----------------------- Open Text... menu item ------------------*/
  841.            /*                                                                 */
  842.            /* (1) Prompt user to save unsaved changes ( if any ).             */
  843.            /* (2) Set the appropriate help resource for this operation.       */
  844.            /* (3) Reformat the latest audio file name as:  x:\pathname\*.ext  */
  845.            /* (4) Request the user to select a file                           */
  846.            /* (5) If the user selected a file, try to open it.                */
  847.            /*-----------------------------------------------------------------*/
  848.  
  849.            case IDM_OPEN_TEXT:
  850.               if ( bUnsavedChanges )                     /* (1) Usaved changes*/
  851.                  if ( SaveChanges( MB_YESNOCANCEL ) == MBID_CANCEL )
  852.                     break;
  853.  
  854.               usFiledlgHelpRes = PANEL_FILEDLG_TEXT;     /* (2) Help resource */
  855.  
  856.               if ( szTextFile[0] )                       /* (3) Format filenam*/
  857.                  FormatFname ( fdgText.szFullFile, szTextFile );
  858.               else
  859.                  strcpy ( fdgText.szFullFile, "*.TXT" );
  860.               fdgText.pszTitle = szTextOpen;             /* Open dialog title */
  861.  
  862.               if (WinFileDlg(HWND_DESKTOP, hwnd, &fdgText))/*(4) Ask for name */
  863.                  if ( fdgText.lReturn == DID_OK )          /* (5) Try loading */
  864.                  {
  865.                     if ( iState == ST_PLAYING ) StopPlaying( hwnd );
  866.                     apiret = LoadTextFile( fdgText.szFullFile );
  867.                     if ( apiret )
  868.                        DisplayDosError ( szErrorMsgTitle, apiret );
  869.                     else
  870.                     {
  871.                        strcpy(szBuffer, szCapFileName);
  872.                        strcat(szBuffer, szNoneFileName);
  873.                        WinSetWindowText( WinWindowFromID( hwnd, ID_CAPTIONTXT),
  874.                                          szBuffer );
  875.  
  876.                        pcTextFile = strrchr( fdgText.szFullFile, '\\' );
  877.                        pcTextFile++;
  878.                        strcpy(szBuffer, szTextFileName);
  879.                        strcat(szBuffer, pcTextFile);
  880.                        WinSetWindowText( WinWindowFromID( hwnd, ID_TEXTTXT),
  881.                                          szBuffer );
  882.                     }
  883.                  }
  884.               break;
  885.  
  886.  
  887.            /*------------ Open Captions... menu item -------------------------*/
  888.            /*                                                                 */
  889.            /* (1) Prompt user to save unsaved changes ( if any ).             */
  890.            /* (2) Set the appropriate help resource for this operation.       */
  891.            /* (3) Reformat the latest caption file name as:  x:\pathname\*.ext*/
  892.            /* (4) Request the user to select a file                           */
  893.            /* (5) If the user selected a file, try to open it.                */
  894.            /*-----------------------------------------------------------------*/
  895.  
  896.            case IDM_OPEN_CAPTIONS:
  897.               if ( bUnsavedChanges )                     /* (1) Unsaved chngs */
  898.                  if ( SaveChanges( MB_YESNOCANCEL ) == MBID_CANCEL ) break;
  899.  
  900.               usFiledlgHelpRes = PANEL_FILEDLG_TEXT;     /* (2) Help resource */
  901.  
  902.               if ( szCaptionFile[0] )                    /* (3) Format filenam*/
  903.                  FormatFname ( fdgText.szFullFile, szCaptionFile );
  904.               else
  905.                  strcpy ( fdgText.szFullFile, "*._CC" );
  906.               fdgText.pszTitle = szCaptionOpen;          /* Open dialog title */
  907.  
  908.               if (WinFileDlg(HWND_DESKTOP, hwnd, &fdgText))/*(4) Ask for name */
  909.                  if ( fdgText.lReturn == DID_OK )          /* (5) Try loading */
  910.                  {
  911.                     if ( iState == ST_PLAYING ) StopPlaying( hwnd );
  912.                     apiret = LoadTextFile( fdgText.szFullFile );
  913.                     if ( apiret )
  914.                        DisplayDosError ( szErrorMsgTitle, apiret );
  915.                     else
  916.                     {
  917.                        strcpy(szBuffer, szTextFileName);
  918.                        strcat(szBuffer, szNoneFileName);
  919.                        WinSetWindowText( WinWindowFromID( hwnd, ID_TEXTTXT),
  920.                                          szBuffer );
  921.  
  922.                        pcTextFile = strrchr( fdgText.szFullFile, '\\' );
  923.                        pcTextFile++;
  924.                        strcpy(szBuffer, szCapFileName);
  925.                        strcat(szBuffer, pcTextFile);
  926.                        WinSetWindowText( WinWindowFromID( hwnd, ID_CAPTIONTXT),
  927.                                          szBuffer );
  928.                     }
  929.                  }
  930.               break;
  931.  
  932.  
  933.            /*------------------ Save menu item -------------------------------*/
  934.            /*                                                                 */
  935.            /* (1) Check for any untimed lines. If any are found, ask the user */
  936.            /*     if he is sure he wants to save.  Exit if user answers No.   */
  937.            /* (2) If we successfully got through step one, save the file.     */
  938.            /*---------------------------------------------------------------- */
  939.  
  940.            case IDM_SAVE:
  941.               if ( CheckForTiming() )
  942.                  SaveCaptionFile ( szCaptionFile, IDM_SAVE );
  943.               break;
  944.  
  945.  
  946.            /*--------------- Save as... menu item ---------------------------*/
  947.            /*                                                                */
  948.            /* (1) Check for any untimed lines. If any are found, ask the user*/
  949.            /*     if he is sure he wants to continue. Exit if user answers NO*/
  950.            /*                                                                */
  951.            /* (2) Format a file name to prompt the user.  If there is a      */
  952.            /*     caption file name (in szCaptionFile), use that name as the */
  953.            /*     basis for the prompt.  If there is a text file name, use   */
  954.            /*     that name as the basis.  The prompt will have the format   */
  955.            /*     of:  x:\pathname\*._CC                                     */
  956.            /*                                                                */
  957.            /* (3) Set up the appropriate Help Resource for the file dialog   */
  958.            /*     box.                                                       */
  959.            /*                                                                */
  960.            /* (4) Display the Save As dialog box to the user.                */
  961.            /*----------------------------------------------------------------*/
  962.  
  963.            case IDM_SAVEAS:
  964.               if ( ! CheckForTiming() ) break; /* (1) Check for untimed lines */
  965.  
  966.               if ( szCaptionFile [0] )         /* (2) Format prompt file name */
  967.                  FormatFname ( fdgSaveAs.szFullFile, szCaptionFile );
  968.               else
  969.               {
  970.                  strcpy ( fdgSaveAs.szFullFile, szTextFile );
  971.                  psz  = (PSZ) strrchr ( fdgSaveAs.szFullFile, '.' );
  972.                  pszSlash = (PSZ) strrchr ( fdgSaveAs.szFullFile, '\\' );
  973.                  if ( pszSlash < psz )  strcpy  ( (char *)psz, "._CC" );
  974.               }
  975.  
  976.               usFiledlgHelpRes = PANEL_FILEDLG_SAVEAS;/*(3)Setup Help Resource*/
  977.  
  978.               DisplaySaveasDlg(IDM_SAVEAS);                     /* (4) */
  979.               break;
  980.  
  981.  
  982.            /*------------------- Exit menu item ------------------------------*/
  983.            /*                                                                 */
  984.            /* (1) Check for any unsaved changes. If any exist, prompt the user*/
  985.            /*     to save them or cancel the Exit request.                    */
  986.            /*                                                                 */
  987.            /* (2) If step 1 went OK, then post a WM_CLOSE message to yourself.*/
  988.            /*-----------------------------------------------------------------*/
  989.  
  990.            case IDM_EXITPROG:
  991.               if ( bUnsavedChanges )
  992.                  if ( SaveChanges( MB_YESNOCANCEL ) == MBID_CANCEL ) break;
  993.  
  994.               bUnsavedChanges = FALSE;
  995.               WinPostMsg( hwnd, WM_CLOSE, 0L, 0L );
  996.               break;
  997.  
  998.  
  999.            /*------------------- Help menu items -----------------------------*/
  1000.            /*                                                                 */
  1001.            /* For each of the Help items, send a message to the help instance */
  1002.            /* object window to display the information the user has requested.*/
  1003.            /*-----------------------------------------------------------------*/
  1004.  
  1005.            case IDM_GENERAL_HELP:
  1006.               WinSendMsg ( hwndHelp, HM_DISPLAY_HELP,
  1007.                        MPFROMSHORT( PANEL_OVERVIEW ),
  1008.                        MPFROMSHORT( HM_RESOURCEID ) );
  1009.               break;
  1010.  
  1011.  
  1012.            case IDM_KEYS_HELP:
  1013.               WinSendMsg ( hwndHelp, HM_DISPLAY_HELP,
  1014.                        MPFROMSHORT( PANEL_KEYS_HELP ),
  1015.                        MPFROMSHORT( HM_RESOURCEID ) );
  1016.               break;
  1017.  
  1018.  
  1019.            case IDM_USING_HELP:
  1020.               WinSendMsg ( hwndHelp, HM_DISPLAY_HELP, 0, 0 );
  1021.               break;
  1022.  
  1023.  
  1024.            case IDM_HELP_INDEX:
  1025.               WinSendMsg ( hwndHelp, HM_HELP_INDEX, 0, 0 );
  1026.               break;
  1027.  
  1028.            case IDM_PRODUCT_INFO:
  1029.               /*
  1030.                * See if the product information dialog box was created.
  1031.                */
  1032.               if (!hwndProductInfo)
  1033.               {
  1034.                  /*
  1035.                   * Product Window was not created, create and display the
  1036.                   * window.
  1037.                   */
  1038.                  hwndProductInfo =
  1039.                      WinLoadSecondaryWindow(
  1040.                         HWND_DESKTOP,              /* Parent of the dialog box*/
  1041.                         hwndMainFrame,             /* Owner of the dialog box.*/
  1042.                         (PFNWP)ProductDlgProc,     /* Dialog box procedure.   */
  1043.                         (HMODULE) NULL,            /* Dialog is where,EXE file*/
  1044.                         ID_DLG_PRODUCTINFO,        /* Dialog ID.              */
  1045.                         (PVOID) NULL);             /* Dialog Creation Params  */
  1046.               }
  1047.               else
  1048.               {
  1049.                  /*
  1050.                   * Product window was created earlier, reposition the window
  1051.                   * and give the focus.
  1052.                   */
  1053.                  WinSetWindowPos(
  1054.                     hwndProductInfo,
  1055.                     HWND_TOP,
  1056.                     (SHORT) NULL,
  1057.                     (SHORT) NULL,
  1058.                     (SHORT) NULL,
  1059.                     (SHORT) NULL,
  1060.                     SWP_RESTORE | SWP_SHOW | SWP_ACTIVATE );
  1061.  
  1062.                  WinSetFocus( HWND_DESKTOP, hwndProductInfo );
  1063.               }
  1064.               break;
  1065.  
  1066.  
  1067.            /*------------- Caption lines... menu items -----------------------*/
  1068.            /*                                                                 */
  1069.            /* Since these menu items do essentially the same thing, they all  */
  1070.            /* invoke the same function ( ResizeTextWindow() ).  For details,  */
  1071.            /* see the ResizeTextWindow() function.                            */
  1072.            /*-----------------------------------------------------------------*/
  1073.  
  1074.            case IDM_2_LINES:
  1075.               ResizeTextWindow(2);
  1076.               break;
  1077.  
  1078.            case IDM_3_LINES:
  1079.               ResizeTextWindow(3);
  1080.               break;
  1081.  
  1082.            case IDM_4_LINES:
  1083.               ResizeTextWindow(4);
  1084.               break;
  1085.  
  1086.            case IDM_5_LINES:
  1087.               ResizeTextWindow(5);
  1088.               break;
  1089.  
  1090.            case IDM_6_LINES:
  1091.               ResizeTextWindow(6);
  1092.               break;
  1093.            }
  1094.         return 0;
  1095.  
  1096.      case WM_CONTROL:
  1097.         sControlID  = SHORT1FROMMP(mp1);
  1098.         usNotifyCode = (USHORT) SHORT2FROMMP(mp1);
  1099.  
  1100.         switch ( sControlID )
  1101.         {
  1102.            /*-------------------- Volume control -----------------------------*/
  1103.            /*                                                                 */
  1104.            /*  (1) Every time the volume control setting is changed, save the */
  1105.            /*      the value in a global variable:  ulVolume.                 */
  1106.            /*                                                                 */
  1107.            /*  (2) send an MCI_SET message to adjust the volume level         */
  1108.            /*-----------------------------------------------------------------*/
  1109.  
  1110.            case ID_VOLUME:
  1111.               if ( ( usNotifyCode == SLN_CHANGE ) ||
  1112.                    ( usNotifyCode == SLN_SLIDERTRACK ) )
  1113.               {
  1114.  
  1115.                  mresult = WinSendMsg( hwndVolume,
  1116.                                        SLM_QUERYSLIDERINFO,
  1117.                                        (MPARAM)MPFROM2SHORT( SMA_SLIDERARMPOSITION,
  1118.                                                              SMA_RANGEVALUE),
  1119.                                        0 );
  1120.                  ulVolume = (ULONG) SHORT1FROMMP( (MPARAM)mresult );/*(1)  */
  1121.  
  1122.                  mspSet.hwndCallback = (HWND) NULL;
  1123.                  mspSet.ulAudio    = MCI_SET_AUDIO_ALL;
  1124.                  mspSet.ulLevel    = (ULONG) ulVolume;
  1125.                  mciSendCommand ( mop.usDeviceID,      /*(2) Adj volume */
  1126.                                   MCI_SET,
  1127.                                   MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
  1128.                                   (PVOID) &mspSet,
  1129.                                   (USHORT) UP_SET );
  1130.               }
  1131.               break;
  1132.  
  1133.  
  1134.            /*----------------- Audio position slider -------------------------*/
  1135.            /*                                                                 */
  1136.            /* (1) As soon as the user drags and/or changes the audio position */
  1137.            /*     slider, we must ignore further MM_MCIPOSITIONCHANGE messages*/
  1138.            /*     coming from the audio play.  We don't want the user and     */
  1139.            /*     MMPM/2 getting into a tug-of-war over the slider position.  */
  1140.            /*     We ignore further MM_MCIPOSITIONCHANGE messages by changing */
  1141.            /*     the value of usPositionUP. Every time an MM_MCIPOSITIONCHANGE*/
  1142.            /*     message is received, its user parameter is compared with    */
  1143.            /*     usPositionUP. If they don't match, the message is ignored.  */
  1144.            /*     By changing usPositionUP, we will cause the program to ignore*/
  1145.            /*     MM_MCIPOSITIONCHANGE messages until the next play is started*/
  1146.            /*                                                                 */
  1147.            /* (2) Now we need to determine if the SLN_CHANGE message came from*/
  1148.            /*     the user or from the program.  To do this, we manipulate the*/
  1149.            /*     window focus.  If the slider window has the focus, that     */
  1150.            /*     implies that the user updated the control.                  */
  1151.            /*                                                                 */
  1152.            /* (3) Set the focus to another window so we can continue to       */
  1153.            /*     distinguish between user and program updates.               */
  1154.            /*                                                                 */
  1155.            /* (4) What we do next depends on the play status of the audio:    */
  1156.            /*                                                                 */
  1157.            /*     (4a) If the audio is stopped, reposition the captions to    */
  1158.            /*          correspond to the new audio position.                  */
  1159.            /*                                                                 */
  1160.            /*     (4b) If the audio is paused, stop the audio and then        */
  1161.            /*          reposition the captions to correspond to the new audio */
  1162.            /*          position.                                              */
  1163.            /*                                                                 */
  1164.            /*     (4c) If the audio is playing, reposition the captions, stop */
  1165.            /*          the audio and then restart it in the new position.     */
  1166.            /*-----------------------------------------------------------------*/
  1167.  
  1168.            case ID_AUDIO_SLIDER:
  1169.               if ( usNotifyCode == SLN_SLIDERTRACK )
  1170.               {
  1171.                  usPositionUP++;
  1172.                  if ( usPositionUP > 32766 )/*(1)Ignore further position change*/
  1173.                     usPositionUP = 0;      /*   messages coming from MMPM/2   */
  1174.                  break;
  1175.               }
  1176.  
  1177.               if ( ( usNotifyCode != SLN_CHANGE ) ||
  1178.                    ( WinQueryFocus ( HWND_DESKTOP ) != hwndAudioSlider ) )
  1179.                  break;                    /*(2)Ignore SLN_CHANGE messages not*/
  1180.                                            /*   originated by the user.       */
  1181.  
  1182.               WinSetFocus(HWND_DESKTOP,hwndVolume);/*(3)Change focus so we can*/
  1183.                                                    /* continue to use test(2) */
  1184.               usPositionUP++;
  1185.               if ( usPositionUP > 32766 )/*Repeat step (1) for SLN_CHANGE msgs */
  1186.                  usPositionUP = 0;
  1187.  
  1188.               sArmPosition = SHORT1FROMMP(mp2);
  1189.  
  1190.               switch ( iState )
  1191.               {                           /* (4) Depending on audio state...  */
  1192.                  case ST_OPEN:
  1193.                     PositionCaptions ( sArmPosition );
  1194.                     break;               /*(4a)Reposition captions and exit or*/
  1195.  
  1196.                  case ST_PAUSED:
  1197.                     StopPlaying( hwnd ); /* (4b) Stop, then reposition or...  */
  1198.                     PositionCaptions ( sArmPosition );
  1199.                     break;
  1200.  
  1201.                  case ST_PLAYING:
  1202.                     PositionCaptions ( sArmPosition );
  1203.                     iState = ST_SEEKING;
  1204.                     StopPlaying( hwnd ); /*(4c)Reposition captions, stop curr */
  1205.                     StartPlaying( hwnd );/*    play and restart at new pos'n  */
  1206.                     break;
  1207.               }
  1208.               break;
  1209.         }
  1210.         break;
  1211.  
  1212.      /*---------------- MM_MCIPOSITIONCHANGE message -------------------------*/
  1213.      /*                                                                       */
  1214.      /* (1) Validate the message by comparing the user parameter with the     */
  1215.      /*     variable usPositionUP. This prevents queued messages from previous*/
  1216.      /*     plays from affecting the Audio Position slider.                   */
  1217.      /*                                                                       */
  1218.      /* (2) Update the position if the audio slider, if we are still playing. */
  1219.      /*                                                                       */
  1220.      /* (3) If we are in Play mode, scan through the line data table to see if*/
  1221.      /*     we need to scroll more lines into the text window.  The index of  */
  1222.      /*     the NEXT line to be displayed can be calculated as follows        */
  1223.      /*                                                                       */
  1224.      /*            Line currently at bottom of window:    usDisplayLine +     */
  1225.      /*            Lines queued to be displayed:          usNextlineReq +     */
  1226.      /*            The line after that one:               1                   */
  1227.      /*-----------------------------------------------------------------------*/
  1228.  
  1229.      case MM_MCIPOSITIONCHANGE:
  1230.         if ((USHORT) SHORT1FROMMP(mp1) != usPositionUP) /* (1) Validate message */
  1231.            break;
  1232.  
  1233.         ulTime = (ULONG) LONGFROMMP(mp2);
  1234.  
  1235.         if ( iState == ST_PLAYING )                 /* (2) Adjust audio slider*/
  1236.         {
  1237.            sArmPosition =
  1238.                (SHORT) ( ( ulTime * ( sAudioArmRange - 1) ) / ulAudioLength );
  1239.            WinSendMsg(
  1240.               hwndAudioSlider,
  1241.               SLM_SETSLIDERINFO,
  1242.               MPFROM2SHORT( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  1243.               MPFROMSHORT( sArmPosition ));
  1244.         }
  1245.  
  1246.         if ( sLatestPlayRequest == ID_PLAY )       /* (3) Time for new line?  */
  1247.         {
  1248.            usTestLine = (USHORT) ( usDisplayLine + usNextlineReq + 1 );
  1249.            pld = (PLINEDATA) pvLinedataTable + usTestLine;
  1250.            while ( ( usTestLine < usLineCount ) && ( pld->ulTime <= ulTime ) )
  1251.            {
  1252.               usNextlineReq++;
  1253.               if ( usNextlineReq == 1 )
  1254.                  WinPostMsg ( hwndText, UM_NEXTLINE, 0, 0 );
  1255.               pld++;
  1256.               usTestLine++;
  1257.            }
  1258.         }
  1259.         return 0;
  1260.  
  1261.      case MM_MCINOTIFY:
  1262.         usNotifyCode    = (USHORT)  SHORT1FROMMP(mp1);
  1263.         usUserParm      = (USHORT)  SHORT2FROMMP(mp1);
  1264.         usCommandMessage = (USHORT) SHORT2FROMMP(mp2);
  1265.  
  1266.         switch ( usCommandMessage )
  1267.         {
  1268.            /*--------------- Play notification message -----------------------*/
  1269.            /*                                                                 */
  1270.            /*  We receive this message when a audio play has completed.       */
  1271.            /*                                                                 */
  1272.            /*  (1) Check to see if the Notification Code portion of the       */
  1273.            /*      message contained an error code.  Display the error code,  */
  1274.            /*      if present.                                                */
  1275.            /*                                                                 */
  1276.            /*  (2) If the notification code was MCI_NOTIFY_SUCCESSFUL, that   */
  1277.            /*      means that the audio has played to the end.  Invoke the    */
  1278.            /*      StopPlaying function to reset all dialog box controls.     */
  1279.            /*      Force the audio slider to its extreme right position, just */
  1280.            /*      in case the granularity of the MM_MCIPOSITIONCHANGE        */
  1281.            /*      messages left it a pixel or two short.                     */
  1282.            /*-----------------------------------------------------------------*/
  1283.  
  1284.            case MCI_PLAY:
  1285.               if ( ( usNotifyCode != MCI_NOTIFY_SUCCESSFUL ) &&
  1286.                    ( usNotifyCode != MCI_NOTIFY_SUPERSEDED ) &&
  1287.                    ( usNotifyCode != MCI_NOTIFY_ABORTED ) )
  1288.               {
  1289.                  ulError = (ULONG)usNotifyCode;/*(1)Display an audio error code*/
  1290.                  StopPlaying( hwnd );
  1291.                  AudioError ( ulError );
  1292.               }
  1293.  
  1294.               if ( usNotifyCode == MCI_NOTIFY_SUCCESSFUL )
  1295.               {                             /* (2) Audio has played to the end*/
  1296.                  StopPlaying( hwnd );
  1297.                  WinSendMsg( hwndAudioSlider, SLM_SETSLIDERINFO,
  1298.                              MPFROM2SHORT( SMA_SLIDERARMPOSITION,
  1299.                                            SMA_RANGEVALUE ),
  1300.                              MPFROMSHORT( (SHORT) ( sAudioArmRange - 1 )));
  1301.               }
  1302.         }
  1303.         return 0;
  1304.  
  1305.  
  1306.      /*-----------------------------------------------------------------------*/
  1307.      /* Every time we get an MM_MCIPASSDEVICE message, we save the state of   */
  1308.      /* the audio device in bAcquired. Whenever the Main window is activated, */
  1309.      /* we check this variable to see if we need to reacquire the audio device*/
  1310.      /*                                                                       */
  1311.      /* (1) If gaining control of the device:                                 */
  1312.      /*                                                                       */
  1313.      /*     (1a) Set bAcquired to FALSE.                                      */
  1314.      /*     (1b) If the latest request was to play start the Play button      */
  1315.      /*          animation.                                                   */
  1316.      /*     (1c) If the latest request was to set timing start the Set Timing */
  1317.      /*          button animation.                                            */
  1318.      /*                                                                       */
  1319.      /* (2) If loosing control of the device:                                 */
  1320.      /*                                                                       */
  1321.      /*     (2a) Set bAcquired to TRUE.                                       */
  1322.      /*     (2b) If the latest request was to play stop the Play button       */
  1323.      /*          animation.                                                   */
  1324.      /*     (2c) If the latest request was to set timing stop the Set Timing  */
  1325.      /*          button animation.                                            */
  1326.      /*                                                                       */
  1327.      /*-----------------------------------------------------------------------*/
  1328.  
  1329.      case MM_MCIPASSDEVICE:
  1330.         if ((USHORT)SHORT1FROMMP(mp2) == MCI_GAINING_USE) /*(1) gaining control */
  1331.         {
  1332.            bAcquired = TRUE;                         /* (1a) gained the device*/
  1333.            if ( (sLatestPlayRequest == ID_PLAY) &&   /* (1b) playing, start.. */
  1334.                 (iState == ST_PLAYING) )
  1335.            {
  1336.               WinSendDlgItemMsg ( hwndMainDlg, ID_PLAY,      /* ...animation  */
  1337.                                   GBM_ANIMATE,
  1338.                                   MPFROMSHORT((SHORT)TRUE),
  1339.                                   MPFROMSHORT((SHORT)FALSE) );
  1340.            }
  1341.            else
  1342.            if ((sLatestPlayRequest==ID_SET_TIMING)&& /*(1c)set timing, start..*/
  1343.                      (iState == ST_PLAYING) )
  1344.            {
  1345.               WinSendDlgItemMsg ( hwndMainDlg, ID_SET_TIMING, /* ...animation*/
  1346.                                   GBM_ANIMATE,
  1347.                                   MPFROMSHORT((SHORT)TRUE),
  1348.                                   MPFROMSHORT((SHORT)FALSE) );
  1349.            }
  1350.  
  1351.         }
  1352.         else                                       /* (2) loosing control     */
  1353.         {
  1354.            bAcquired = FALSE;                      /* (2a) lost the device.   */
  1355.            if ( (sLatestPlayRequest == ID_PLAY) &&   /* (1b) playing, start.. */
  1356.                 (iState == ST_PLAYING) )
  1357.            {
  1358.               WinSendDlgItemMsg( hwndMainDlg, ID_PLAY,       /* ...animation  */
  1359.                                  GBM_ANIMATE,
  1360.                                  MPFROMSHORT((SHORT)FALSE),
  1361.                                  MPFROMSHORT((SHORT)FALSE) );
  1362.            }
  1363.            else
  1364.            if ((sLatestPlayRequest==ID_SET_TIMING)&& /*(1c)set timing, start..*/
  1365.                      (iState == ST_PLAYING) )
  1366.            {
  1367.               WinSendDlgItemMsg( hwndMainDlg, ID_SET_TIMING, /* ...animation */
  1368.                                  GBM_ANIMATE,
  1369.                                  MPFROMSHORT((SHORT)FALSE),
  1370.                                  MPFROMSHORT((SHORT)FALSE) );
  1371.            }
  1372.         }
  1373.         return 0;
  1374.  
  1375.      /*-----------------------------------------------------------------------*/
  1376.      /* Before closing the Main window, check to see if the user wants to save*/
  1377.      /* any unsaved timing changes. Then close the device and return          */
  1378.      /* WinDefWindowProc to make sure a WM_QUITmessage is sent and we fall out*/
  1379.      /* of the message loop.                                                  */
  1380.      /*-----------------------------------------------------------------------*/
  1381.  
  1382.      case WM_CLOSE:
  1383.         if ( bUnsavedChanges )
  1384.         {
  1385.            if ( SaveChanges( MB_YESNO ) == MBID_CANCEL )
  1386.               return 0;
  1387.         }
  1388.         if (iState != ST_CLOSED)
  1389.         {
  1390.            CloseAudioDevice( hwnd );
  1391.         }
  1392.         return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  1393.   }
  1394.   return WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 );
  1395. }
  1396.  
  1397. /******************************************************************************
  1398.  * Name         : TextWindowProc
  1399.  *
  1400.  * Description  : This function controls the text window.  It will handle
  1401.  *                received messages such as paint, timing events, etc.
  1402.  *
  1403.  * Parameters   : hwnd - Handle for the Main dialog box.
  1404.  *                msg  - Message received by the dialog box.
  1405.  *                mp1  - Parameter 1 for the just received message.
  1406.  *                mp2  - Parameter 2 for the just received message.
  1407.  *
  1408.  * Return       :
  1409.  *
  1410.  ******************************************************************************/
  1411. MRESULT EXPENTRY TextWindowProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  1412. {
  1413.    HPS          hpsPaint;               /* Handle to Text window pres space   */
  1414.    RECTL        rclPaint;               /* Area of the Text window            */
  1415.    POINTL       aptlPaint[4];           /* for bitblt                         */
  1416.  
  1417.  
  1418.    switch ( msg )
  1419.    {
  1420.       /*--------------------- Paint text window ------------------------------*/
  1421.       /*                                                                      */
  1422.       /*  The text to be painted into the text window is held in a monochrome */
  1423.       /*  bitmap whose presentation space is hpsText.                         */
  1424.       /*                                                                      */
  1425.       /*  (1) Setup blitting rectangles based on the area to be painted and   */
  1426.       /*      the scroll offset.  These rectangles are identical, except for  */
  1427.       /*      the Y-coordinates of the source rectangle.  These are Scroll    */
  1428.       /*      Offset pixels greater than the destination.  While scrolling,   */
  1429.       /*      the Scroll Offset grows continually smaller, meaning that the   */
  1430.       /*      source blitting rectangle scrolls DOWN the bitmap, while the    */
  1431.       /*      text in the window appears to scroll UP.)                       */
  1432.       /*                                                                      */
  1433.       /*  (2) Set the foreground and background colors of the Paint           */
  1434.       /*      presentation space to control the color of the background and   */
  1435.       /*      the text as it is blitted to the window.                        */
  1436.       /*----------------------------------------------------------------------*/
  1437.  
  1438.       case WM_PAINT:
  1439.          hpsPaint = WinBeginPaint ( hwnd, 0, &rclPaint );
  1440.  
  1441.          aptlPaint[0].x = rclPaint.xLeft;    /* (1) Set blit rect coordinates */
  1442.          aptlPaint[0].y = rclPaint.yBottom;
  1443.          aptlPaint[1].x = rclPaint.xRight;
  1444.          aptlPaint[1].y = rclPaint.yTop;
  1445.          aptlPaint[2].x = rclPaint.xLeft;
  1446.          aptlPaint[2].y = rclPaint.yBottom + lScrollOffset;
  1447.          aptlPaint[3].x = rclPaint.xRight;
  1448.          aptlPaint[3].y = rclPaint.yTop + lScrollOffset;
  1449.  
  1450.          GpiSetColor( hpsPaint, CLR_WHITE );    /* (2) Set background color...*/
  1451.          GpiSetBackColor( hpsPaint, CLR_DARKBLUE ); /*  ... and Text color    */
  1452.  
  1453.          GpiBitBlt(
  1454.             hpsPaint,
  1455.             hpsText,
  1456.             4,
  1457.             aptlPaint,
  1458.             ROP_SRCCOPY,
  1459.             BBO_IGNORE );
  1460.          WinEndPaint( hpsPaint );
  1461.          return (MRESULT) 1;
  1462.  
  1463.  
  1464.       /*---------------------- WM_TIMER message ------------------------------*/
  1465.       /*                                                                      */
  1466.       /*  The text window receives a WM_TIMER message whenever it is necessary*/
  1467.       /*  to scroll one more scroll increment.  When it is not scrolling, the */
  1468.       /*  timer is stopped, and no messages are received.                     */
  1469.       /*                                                                      */
  1470.       /*  (1) Decrement the Scroll Offset by the Scroll Increment.            */
  1471.       /*                                                                      */
  1472.       /*  (2) Scroll the Text window UP by the Scroll Increment.              */
  1473.       /*                                                                      */
  1474.       /*  (3) Check to see if one complete text line has been scrolled.  This */
  1475.       /*      is true if the Scroll Offset is zero.  If so:                   */
  1476.       /*                                                                      */
  1477.       /*      (3a) Stop the timer for now.                                    */
  1478.       /*                                                                      */
  1479.       /*      (3b) Decrement the number of lines queued for scrolling         */
  1480.       /*           ( usNextlineReq ).                                         */
  1481.       /*                                                                      */
  1482.       /*      (3c) If lines remain to be scrolled, send a message to yourself,*/
  1483.       /*           requesting that another line be scrolled into the window.  */
  1484.       /*           If no lines remain to be scrolled AND we are in a Start    */
  1485.       /*           Timing operation, then unhighlight the Advance Line button.*/
  1486.       /*----------------------------------------------------------------------*/
  1487.  
  1488.       case WM_TIMER:
  1489.          lScrollOffset -= CC_SCROLL_INC;         /* (1) Decrement scroll offst*/
  1490.  
  1491.          WinScrollWindow(                        /* (2) Scroll window up      */
  1492.             hwnd,
  1493.             0,
  1494.             CC_SCROLL_INC,
  1495.             NULL,
  1496.             NULL,
  1497.             0,
  1498.             NULL,
  1499.             SW_INVALIDATERGN );
  1500.  
  1501.          if ( lScrollOffset == 0 )                /* (3) Finished line?  */
  1502.          {
  1503.             WinStopTimer ( hab, hwnd, CC_TIMER_ID );   /* (3a) Stop timer     */
  1504.             if ( usNextlineReq )                 /* (3b) Decrement queued lns */
  1505.                usNextlineReq--;
  1506.             if ( usNextlineReq )                 /* (3c) See if more lines    */
  1507.                WinSendMsg( hwnd, UM_NEXTLINE, 0, 0 ); /* need to be scrolled  */
  1508.             else
  1509.                if ( sLatestPlayRequest == ID_SET_TIMING )
  1510.                   WinSendDlgItemMsg (            /* Unhighlight Advance Line  */
  1511.                      hwndMainDlg,
  1512.                      ID_NEXTLINE,
  1513.                      GBM_SETBITMAPINDEX,
  1514.                      MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1515.          }
  1516.          break;
  1517.  
  1518.  
  1519.       /*------------------------ UM_NEXTLINE ---------------------------------*/
  1520.       /*                                                                      */
  1521.       /*  This message requests the Text window to scroll the next line of    */
  1522.       /*  text into the window.                                               */
  1523.       /*                                                                      */
  1524.       /*  (1) Increment the index of the bottom-most line which is to be      */
  1525.       /*      displayed in the text window. ( usDisplayLine )                 */
  1526.       /*                                                                      */
  1527.       /*  (2) Redraw the backup text bitmap with the new line of text at the  */
  1528.       /*      bottom.                                                         */
  1529.       /*                                                                      */
  1530.       /*  (3) Initialize the scroll offset to the Line Spacing.               */
  1531.       /*                                                                      */
  1532.       /*  (4) Start the timer.  As each WM_TIMER message is received, the text*/
  1533.       /*      window will scroll up by one Scroll Increment                   */
  1534.       /*----------------------------------------------------------------------*/
  1535.  
  1536.       case UM_NEXTLINE:
  1537.          usDisplayLine++;                       /* (1) Inc Display Line Index */
  1538.          DisplayTextLine();                     /* (2) Redraw backup bitmap   */
  1539.          lScrollOffset = lLineSpacing;          /* (3) Initialize scroll offst*/
  1540.          WinStartTimer( hab, hwnd, CC_TIMER_ID, 100 );/* (4) Start the timer. */
  1541.          return 0;
  1542.  
  1543.    }
  1544.    return WinDefWindowProc ( hwnd, msg, mp1, mp2 );
  1545. }
  1546.  
  1547.  
  1548. /******************************************************************************
  1549.  * Name         : FileFilterProc
  1550.  *
  1551.  * Description  : This function filters the messages to the File dialog
  1552.  *                procedure.  It intercepts WM_HELP messages and invokes the
  1553.  *                help screen when it encounters.
  1554.  *
  1555.  * Parameters   : hwnd - Handle for the Main dialog box.
  1556.  *                msg  - Message received by the dialog box.
  1557.  *                mp1  - Parameter 1 for the just received message.
  1558.  *                mp2  - Parameter 2 for the just received message.
  1559.  *
  1560.  * Return       :
  1561.  *
  1562.  ******************************************************************************/
  1563. MRESULT EXPENTRY FileFilterProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  1564. {
  1565.    CHAR szError[ERROR_LENGTH];
  1566.  
  1567.  
  1568.    if ( msg == WM_HELP )
  1569.    {
  1570.       if ( WinSendMsg ( hwndHelp, HM_DISPLAY_HELP,
  1571.                         MPFROMSHORT ( (SHORT) usFiledlgHelpRes ),
  1572.                         MPFROMSHORT ( HM_RESOURCEID ) ) )
  1573.       {
  1574.          WinLoadString ( hab, (HMODULE)NULL, STRID_HELP_CREATION_FAILED,
  1575.                          ERROR_LENGTH, szError );
  1576.  
  1577.          WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szErrorMsgTitle,
  1578.                                           0, MB_OK | MB_ERROR | MB_MOVEABLE);
  1579.       }
  1580.       return (MRESULT) FALSE;
  1581.    }
  1582.    return WinDefFileDlgProc( hwnd, msg, mp1, mp2 ) ;
  1583. }
  1584.  
  1585.  
  1586. /******************************************************************************
  1587.  * Name         : FormatFname
  1588.  *
  1589.  * Description  : This function format the file name for the dialog boxes.
  1590.  *                This function accepts a name of the from x:\path\file.ext
  1591.  *                and returns a name of the form x:\path\*.ext
  1592.  *
  1593.  * Parameters   : szInputName  - accepted file name
  1594.  *                szOutputName - returned file name
  1595.  *
  1596.  * Return       : none.
  1597.  *
  1598.  ******************************************************************************/
  1599. VOID FormatFname ( CHAR szOutputName[], CHAR szInputName[] )
  1600. {
  1601.    CHAR   szWorkName[CCHMAXPATH];
  1602.    PCHAR  pcharStart, pcharEnd;
  1603.  
  1604.  
  1605.    strcpy ( szWorkName, szInputName );
  1606.  
  1607.    pcharEnd = strrchr ( szWorkName, (int) '\\' );
  1608.    if ( pcharEnd )
  1609.    {                                      /*----------------------------------*/
  1610.       *pcharEnd = 0;                      /* A directory name (and possibly a */
  1611.       strcpy ( szOutputName, szWorkName );/* drive letter) was present.  Copy */
  1612.       strcat ( szOutputName, "\\" );      /* these to the output name.        */
  1613.       pcharStart = pcharEnd + 1;          /*----------------------------------*/
  1614.    }
  1615.    else
  1616.    {
  1617.       pcharEnd = strrchr ( szWorkName, (int) ':' );
  1618.       if ( pcharEnd )
  1619.       {                                     /*--------------------------------*/
  1620.          *pcharEnd = 0;                     /*No directory found, but there IS*/
  1621.          strcpy ( szOutputName, szWorkName);/*a drive letter. Copy the drive  */
  1622.          strcat ( szOutputName, ":" );      /*letter to the output name.      */
  1623.          pcharStart = pcharEnd + 1;         /*--------------------------------*/
  1624.       }
  1625.       else
  1626.       {                                      /*-------------------------------*/
  1627.          szOutputName[0] = 0;                /* No directory or drive letter  */
  1628.          pcharStart = szWorkName;            /* was present.                  */
  1629.       }                                      /*-------------------------------*/
  1630.    }
  1631.  
  1632.    strcat ( szOutputName, "*" );        /* Now tack on the new file name: "*" */
  1633.  
  1634.    pcharEnd = strrchr ( pcharStart, '.' );   /*-------------------------------*/
  1635.    if ( pcharEnd )                           /*Tack on the original extension,*/
  1636.       strcat ( szOutputName, pcharEnd );     /*if present.                    */
  1637. }                                            /*-------------------------------*/
  1638.  
  1639. /******************************************************************************
  1640.  * Name         : LoadAudioFile
  1641.  *
  1642.  * Description  : This function will open the audio device with a selected
  1643.  *                audio file, if the audio device is not opened.  If the
  1644.  *                audio device is open, the selected audio file will be loaded
  1645.  *                onto it.  Also querys the length of the audio file, calibrates
  1646.  *                the scale on the audio slider and position the captions at
  1647.  *                the beginning of the caption file.
  1648.  *
  1649.  * Concepts     : - Open a device using the MCi interface.
  1650.  *                - Loading a file into an already open device.
  1651.  *
  1652.  * MMPM/2 API's : mciSendCommand  MCI_OPEN
  1653.  *                                MCI_LOAD
  1654.  *                                MCI_STATUS
  1655.  *
  1656.  * Parameters   : hwnd       - main window handle
  1657.  *                szFilename - selected audio file
  1658.  *
  1659.  * Return       : ulError    - if an error occured.
  1660.  *
  1661.  ******************************************************************************/
  1662. ULONG LoadAudioFile ( HWND hwnd, CHAR szFilename[] )
  1663. {
  1664.    ULONG   ulError;
  1665.    CHAR    szAudioPosSeconds[TITLE_LENGTH];     /* Title for Audio Slider     */
  1666.    CHAR    szAudioPosMinutes[TITLE_LENGTH];     /* Title for Audio Slider     */
  1667.    ULONG   ulAudioLengthMsec;                   /* For audio length in Msec   */
  1668.    ULONG   ulAudioLengthSec;                    /* For audio length in Sec    */
  1669.    ULONG   ulAudioLengthMin;                    /* For audio length in Minutes*/
  1670.    CHAR    szAudioLength[10];                   /* For audio length           */
  1671.    CHAR    szAudioMin[10];                      /* Audio length in ASCII      */
  1672.    CHAR    szAudioSec[10];                      /* Audio length in ASCII      */
  1673.    MRESULT mresult;                             /* for slider result          */
  1674.    PCHAR   pcAudioFile;                         /* audio file name            */
  1675.    CHAR    szBuffer[CCHMAXPATH];                /* buffer to hold file name   */
  1676.    static  MCI_LOAD_PARMS     mlp;              /* Load params                */
  1677.  
  1678.  
  1679.    /* If the audio device is closed, open it.  */
  1680.    if ( iState == ST_CLOSED )
  1681.    {
  1682.       mop.hwndCallback     = hwndMainDlg;         /*--------------------------*/
  1683.       mop.usDeviceID       = (USHORT)  NULL;      /*     Attempt to open      */
  1684.       mop.pszDeviceType    = (PSZ)NULL;           /*    the digital audio     */
  1685.       mop.pszElementName   = (PSZ)szFilename;     /*         device.          */
  1686.       ulError = mciSendCommand ( (USHORT) 0,      /*--------------------------*/
  1687.                                  MCI_OPEN,
  1688.                                  MCI_WAIT | MCI_OPEN_SHAREABLE |
  1689.                                  MCI_OPEN_ELEMENT | MCI_READONLY,
  1690.                                  (PVOID) &mop,
  1691.                                  (USHORT) UP_OPEN );
  1692.  
  1693.       if ( ulError )
  1694.       {
  1695.          CloseAudioDevice( hwnd );
  1696.          return ulError;
  1697.       }
  1698.    }
  1699.    else
  1700.    {
  1701.       mlp.hwndCallback     = (HWND) NULL;         /*--------------------------*/
  1702.       mlp.pszElementName   = (PSZ)szFilename;     /*     Attempt to load the  */
  1703.       ulError =                                   /*     requested audio file */
  1704.         mciSendCommand( (USHORT) mop.usDeviceID,  /*--------------------------*/
  1705.                         MCI_LOAD,
  1706.                         MCI_WAIT | MCI_READONLY,
  1707.                         (PVOID) &mlp,
  1708.                         (USHORT) UP_LOAD );
  1709.  
  1710.       if ( ulError )
  1711.       {
  1712.          CloseAudioDevice( hwnd );
  1713.          return ulError;
  1714.       }
  1715.    }
  1716. /*---------------  The load attempt was successful  --------------------------*/
  1717. /*                                                                            */
  1718. /* (1) Set the program state switches and the dialog-box status window to     */
  1719. /*     reflect the new state.                                                 */
  1720. /*                                                                            */
  1721. /* (2) Ask MMPM/2 how long the audio file is ( in MM units ) and use this     */
  1722. /*     number to calibrate the scale on the audio slider.  The scale is       */
  1723. /*     calibrated in seconds if the length is less than 60 seconds, and in    */
  1724. /*     minutes and seconds if the length is 60 seconds or greater.  Set the   */
  1725. /*     audio slider bar all the way to the left.                              */
  1726. /*                                                                            */
  1727. /* (3) Position the captions at the beginning of the caption file.            */
  1728. /*                                                                            */
  1729. /* (4) Enable the Rewind button and possibly the Start Timing and Play buttons*/
  1730. /*     in the dialog box.                                                     */
  1731. /*                                                                            */
  1732. /*----------------------------------------------------------------------------*/
  1733.  
  1734.    iState       = ST_OPEN;                        /* (1) Set state switches.. */
  1735.  
  1736.    bAudioLoaded = TRUE;
  1737.  
  1738.    msp.hwndCallback = (HWND) NULL;                 /*-------------------------*/
  1739.    msp.ulItem     = MCI_STATUS_LENGTH;             /* (2)  Ascertain the      */
  1740.    mciSendCommand ( (USHORT) mop.usDeviceID,       /*    play length of the   */
  1741.                     MCI_STATUS,                    /*       audio file.       */
  1742.                     MCI_WAIT | MCI_STATUS_ITEM,    /*-------------------------*/
  1743.                     (PVOID) &msp,
  1744.                     (USHORT) UP_STATUS );
  1745.  
  1746.    ulAudioLength     = msp.ulReturn;                 /*-----------------------*/
  1747.                                                      /* (2) Initialize the    */
  1748.    ulAudioLengthMsec = MSECFROMMM ( ulAudioLength ); /*     audio position    */
  1749.    ulAudioLengthSec  = ulAudioLengthMsec / 1000;     /*     slider control    */
  1750.                                                      /*-----------------------*/
  1751.    if ( ulAudioLengthSec >= 60 )
  1752.    {
  1753.       ulAudioLengthSec %= 60;
  1754.       ulAudioLengthMin  = ( ulAudioLengthMsec / 60000 );
  1755.       sprintf(szAudioLength, "%01lu:%02lu", ulAudioLengthMin, ulAudioLengthSec);
  1756.       WinLoadString( hab, 0, STRID_AUDIO_POS_MINUTES,
  1757.                      TITLE_LENGTH, szAudioPosMinutes );
  1758.       WinSetWindowText( WinWindowFromID( hwnd, ID_AUDIO_POSITION ),
  1759.                         szAudioPosMinutes );
  1760.    }
  1761.    else
  1762.    {
  1763.       sprintf ( szAudioLength, "%lu", ulAudioLengthSec );
  1764.       WinLoadString( hab, 0, STRID_AUDIO_POS_SECONDS,TITLE_LENGTH,
  1765.                          szAudioPosSeconds );
  1766.       WinSetWindowText ( WinWindowFromID( hwnd, ID_AUDIO_POSITION ),
  1767.                          szAudioPosSeconds );
  1768.    }
  1769.  
  1770.    WinEnableWindow   ( hwndAudioSlider, TRUE );
  1771.  
  1772.    WinSendMsg ( hwndAudioSlider, SLM_SETSCALETEXT,
  1773.                 MPFROMSHORT ( (SHORT) ( AUDIO_SLIDER_TICKS - 1 ) ),
  1774.                 MPFROMP ( szAudioLength ) );
  1775.    WinSendMsg ( hwndAudioSlider, SLM_SETSCALETEXT, 0,
  1776.                 MPFROMP ( "0" ) );
  1777.    WinSendMsg ( hwndAudioSlider, SLM_SETSLIDERINFO,
  1778.                 MPFROM2SHORT ( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  1779.                 MPFROMSHORT  ( 0 ) );
  1780.    mresult = WinSendMsg( hwndAudioSlider, SLM_QUERYSLIDERINFO,
  1781.                          MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), 0);
  1782.    sAudioArmRange = SHORT2FROMMP ( (MPARAM) mresult );
  1783.  
  1784.    PositionCaptions ( 0 );                  /* (3) Position captions at start */
  1785.  
  1786.                                             /* (4) Enable dlg box pushbuttons */
  1787.    WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_REWIND ), TRUE );
  1788.  
  1789.    if ( bTextLoaded )
  1790.       WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_SET_TIMING ), TRUE );
  1791.    if ( bCaptionsLoaded )
  1792.       WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_PLAY ), TRUE );
  1793.  
  1794.    pcAudioFile = strrchr( szFilename, '\\' );
  1795.    pcAudioFile++;
  1796.    strcpy(szBuffer, szAudioFileName);
  1797.    strcat(szBuffer, pcAudioFile);
  1798.    WinSetWindowText( WinWindowFromID( hwnd, ID_AUDIOTXT), szBuffer );
  1799.  
  1800.    return ulError;
  1801. }
  1802.  
  1803.  
  1804. /******************************************************************************
  1805.  * Name         : StartPlaying
  1806.  *
  1807.  * Description  : This function will begin the playing of an audio file from
  1808.  *                the location indicated by the audio slider and it will
  1809.  *                continue until the end of file. It is invoked when the user
  1810.  *                selects the Start timing or Play pushbutton on the Captions
  1811.  *                main window.
  1812.  *
  1813.  * Concepts     : Playing an audio file using MCI interface.
  1814.  *
  1815.  * MMPM/2 API's : mciSendCommand  MCI_PLAY
  1816.  *
  1817.  * Parameters   : hwnd       - main window handle
  1818.  *
  1819.  * Return       : ulError    - if an error occured.
  1820.  *
  1821.  ******************************************************************************/
  1822. ULONG StartPlaying ( HWND hwnd )
  1823. {
  1824.    static  MCI_PLAY_PARMS   mpp;       /* parms for MCI_PLAY                  */
  1825.    static  MCI_POSITION_PARMS mppPos;  /* parms for MCI_SET_POSITION_ADVISE   */
  1826.    ULONG   ulError;                    /* Return code                         */
  1827.    MRESULT mresultSlider; /*--------------------------------------------------*/
  1828.    SHORT   sArmPosition;  /*Read the slider position to determine the start of*/
  1829.    ULONG   ulStartPos;    /*the audio play. If the slider is at the extreme   */
  1830.                           /*right of its range, start over at the beginning.  */
  1831.                           /*--------------------------------------------------*/
  1832.  
  1833.    mresultSlider =
  1834.           WinSendMsg( hwndAudioSlider, SLM_QUERYSLIDERINFO,
  1835.                       MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_RANGEVALUE), 0 );
  1836.    sArmPosition = SHORT1FROMMP ( (MPARAM) mresultSlider );
  1837.  
  1838.    if ( sArmPosition >=  ( sAudioArmRange - 1 ) )
  1839.    {
  1840.       ulStartPos = 0;
  1841.       WinSendMsg( hwndAudioSlider, SLM_SETSLIDERINFO,
  1842.                   MPFROM2SHORT ( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  1843.                   MPFROMSHORT  ( 0 ) );
  1844.       PositionCaptions ( 0 );
  1845.    }
  1846.    else
  1847.       ulStartPos = (ULONG)((sArmPosition * ulAudioLength)/(sAudioArmRange - 1));
  1848.  
  1849.  
  1850.    mpp.hwndCallback = hwndMainDlg;
  1851.    mpp.ulFrom = ulStartPos;
  1852.    ulError =  mciSendCommand ( mop.usDeviceID,        /*--------------------*/
  1853.                                MCI_PLAY,              /*          Start     */
  1854.                                MCI_NOTIFY | MCI_FROM, /*         playback.  */
  1855.                                (PVOID) &mpp,          /*--------------------*/
  1856.                                (USHORT) UP_PLAY );
  1857.  
  1858.    if ( ulError )
  1859.    {
  1860.       StopPlaying( hwnd );
  1861.       return ulError;
  1862.    }
  1863.  
  1864.  
  1865.  /*------------------------------------------------------------------------*/
  1866.  /*                                                                        */
  1867.  /*         If there were no errors starting the play:                     */
  1868.  /*                                                                        */
  1869.  /*        (1) Request position advise messages.                           */
  1870.  /*        (2) Enable PAUSE and STOP controls.                             */
  1871.  /*        (3) Begin animating the button that started the play            */
  1872.  /*            ( either PLAY or SET TIMING )                               */
  1873.  /*                                                                        */
  1874.  /*------------------------------------------------------------------------*/
  1875.  
  1876.    iState = ST_PLAYING;                    /* Set state to reflect play mode */
  1877.  
  1878.    mppPos.hwndCallback = hwndMainDlg;      /*-----------------------------*/
  1879.    mppPos.ulUnits    = 1500;               /* (1) Request position advise */
  1880.    mppPos.usUserParm = usPositionUP;       /*             messages.       */
  1881.    mppPos.Reserved0  = 0;                  /*-----------------------------*/
  1882.    mciSendCommand    ( mop.usDeviceID,
  1883.                        MCI_SET_POSITION_ADVISE,
  1884.                        MCI_NOTIFY | MCI_SET_POSITION_ADVISE_ON,
  1885.                        (PVOID) &mppPos,
  1886.                        UP_POSITION );
  1887.  
  1888.    WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_PAUSE  ), TRUE  );/*(2) */
  1889.    WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_STOP   ), TRUE  );
  1890.  
  1891.    switch ( sLatestPlayRequest )        /* (3) Start animating the button that*/
  1892.       {                                 /*     initiated the play operation.  */
  1893.       case ID_SET_TIMING:
  1894.          WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_PLAY ), FALSE );
  1895.          WinSendDlgItemMsg(hwndMainDlg, ID_SET_TIMING, GBM_ANIMATE,
  1896.                            MPFROMSHORT((SHORT)TRUE), MPFROMSHORT((SHORT)FALSE));
  1897.          WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_NEXTLINE ), TRUE );
  1898.          WinSendDlgItemMsg(hwndMainDlg, ID_NEXTLINE, GBM_SETBITMAPINDEX,
  1899.                            MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1900.          break;
  1901.  
  1902.       case ID_PLAY:
  1903.          WinEnableWindow( WinWindowFromID( hwndMainDlg, ID_SET_TIMING ), FALSE);
  1904.          WinSendDlgItemMsg(hwndMainDlg, ID_PLAY, GBM_ANIMATE,
  1905.                            MPFROMSHORT((SHORT)TRUE), MPFROMSHORT((SHORT)FALSE));
  1906.    }
  1907.    return ulError;
  1908. }
  1909.  
  1910. /******************************************************************************
  1911.  * Name         : StopPlaying
  1912.  *
  1913.  * Description  : This function will stop the device that is playing.
  1914.  *
  1915.  * Concepts     : Stopping a device using MCI interface.
  1916.  *
  1917.  * MMPM/2 API's : mciSendCommand  MCI_STOP
  1918.  *
  1919.  * Parameters   : hwnd       - main window handle
  1920.  *
  1921.  * Return       : none.
  1922.  *
  1923.  ******************************************************************************/
  1924. VOID StopPlaying ( HWND hwnd )
  1925. {
  1926.    /***************************************************************************/
  1927.    /*                                                                         */
  1928.    /* (1) Send a message to MMPM/2 requesting the current play to stop.       */
  1929.    /*                                                                         */
  1930.    /* (2) Update the internal status to indicate that the play has stopped.   */
  1931.    /*     Show the new state in the status line in the main dialog box.       */
  1932.    /*                                                                         */
  1933.    /* (3) Disable the Pause, Stop and Advance Line controls                   */
  1934.    /*                                                                         */
  1935.    /* (4) Stop animating the button which requested the audio play ( either   */
  1936.    /*     Play or Start Timing ).                                             */
  1937.    /*                                                                         */
  1938.    /* (5) Enable the File, Help and Options submenus.                         */
  1939.    /***************************************************************************/
  1940.  
  1941.    usNextlineReq  = 0;
  1942.    mgp.hwndCallback = 0;                /*-------------------------------------*/
  1943.    mciSendCommand ( mop.usDeviceID,     /*                                     */
  1944.                     MCI_STOP,           /*(1) Issue an MCI_STOP command for the*/
  1945.                     MCI_WAIT,           /*    audio file.                      */
  1946.                     (PVOID) &mgp,       /*                                     */
  1947.                     (USHORT) UP_STOP ); /*-------------------------------------*/
  1948.  
  1949.    iState = ST_OPEN;                   /*(2) Update internal & external status*/
  1950.  
  1951.    WinSendDlgItemMsg( hwndMainDlg, ID_PAUSE, GBM_SETBITMAPINDEX,
  1952.                                  MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1953.    WinSendDlgItemMsg( hwndMainDlg, ID_NEXTLINE, GBM_SETBITMAPINDEX,
  1954.                                  MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1955.  
  1956.    WinEnableWindow ( WinWindowFromID( hwndMainDlg, ID_PAUSE   ), FALSE );
  1957.    WinEnableWindow ( WinWindowFromID( hwndMainDlg, ID_STOP    ), FALSE );/*(3)*/
  1958.    WinEnableWindow ( WinWindowFromID( hwndMainDlg, ID_NEXTLINE), FALSE );
  1959.  
  1960.    switch ( sLatestPlayRequest )      /* (4) Stop animating the graphic button*/
  1961.    {                                  /*     which started the PLAY operation.*/
  1962.       case ID_SET_TIMING:
  1963.          WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_PLAY ), TRUE );
  1964.          WinSendDlgItemMsg ( hwndMainDlg, ID_SET_TIMING, GBM_ANIMATE,
  1965.                              MPFROMSHORT((SHORT)FALSE),
  1966.                              MPFROMSHORT((SHORT)FALSE) );
  1967.          break;
  1968.  
  1969.       case ID_PLAY:
  1970.          WinEnableWindow( WinWindowFromID( hwndMainDlg, ID_SET_TIMING ), TRUE);
  1971.          WinSendDlgItemMsg ( hwndMainDlg, ID_PLAY, GBM_ANIMATE,
  1972.                              MPFROMSHORT((SHORT)FALSE),
  1973.                              MPFROMSHORT((SHORT)FALSE) );
  1974.    }
  1975.    bAcceptPlayRequests = TRUE;
  1976. }
  1977.  
  1978. /******************************************************************************
  1979.  * Name         : CloseAudioDevice
  1980.  *
  1981.  * Description  : This function will close the audio device.
  1982.  *
  1983.  * Concepts     : Closing a device using MCI interface.
  1984.  *
  1985.  * MMPM/2 API's : mciSendCommand  MCI_CLOSE
  1986.  *
  1987.  * Parameters   : hwnd       - main window handle
  1988.  *
  1989.  * Return       : none.
  1990.  *
  1991.  ******************************************************************************/
  1992. VOID CloseAudioDevice ( HWND hwnd )
  1993. {
  1994.    mgp.hwndCallback = (HWND) NULL;       /*-----------------------------------*/
  1995.    mciSendCommand ( mop.usDeviceID,      /*                                   */
  1996.                     MCI_CLOSE,           /*                                   */
  1997.                     MCI_WAIT,            /* Close the digital audio device.   */
  1998.                     (PVOID) &mgp,        /*                                   */
  1999.                     (USHORT) UP_CLOSE ); /*                                   */
  2000.                                          /*-----------------------------------*/
  2001.    iState            = ST_CLOSED;
  2002. }
  2003.  
  2004.  
  2005. /******************************************************************************
  2006.  * Name         : ShareAudioDevice
  2007.  *
  2008.  * Description  : This function will control audio device sharing.
  2009.  *                Every time the activation status of the main window changes,
  2010.  *                this function will be invoked to see if we needed to regain
  2011.  *                the control of the audio device.
  2012.  *
  2013.  * Concepts     : Sharing a audio device using MCI interface.
  2014.  *
  2015.  * MMPM/2 API's : mciSendCommand  MCI_ACQUIREDEVICE
  2016.  *
  2017.  * Parameters   : none.
  2018.  *
  2019.  * Return       : none.
  2020.  *
  2021.  ******************************************************************************/
  2022. VOID ShareAudioDevice ( void )
  2023. {
  2024.  
  2025.    if ( bMainActive && ( iState != ST_CLOSED ) && ! bAcquired )
  2026.    {
  2027.       mgp.hwndCallback = hwndMainDlg;     /*----------------------------------*/
  2028.       mciSendCommand( mop.usDeviceID,     /*Request the device if:            */
  2029.                       MCI_ACQUIREDEVICE,  /* (a) Either window active   AND...*/
  2030.                       (ULONG)MCI_NOTIFY,  /* (b) We have the device open AND..*/
  2031.                       (PVOID) &mgp,       /* (c) We don't own the device    . */
  2032.                       (USHORT)NULL);      /*----------------------------------*/
  2033.    }
  2034. }
  2035.  
  2036.  
  2037. /******************************************************************************
  2038.  * Name         : AudioError
  2039.  *
  2040.  * Description  : This function will display the MCI error message based upon
  2041.  *                the ulError return code.  The MCI function mciGetErrorString
  2042.  *                is used to convert the error code into a text string. The
  2043.  *                resulting string will displayed to the user.
  2044.  *
  2045.  * Concepts     : Using mciGetErrorString to convert an error code into a
  2046.  *                textual message.
  2047.  *
  2048.  * MMPM/2 API's : mciGetErrorString
  2049.  *
  2050.  * Parameters   : ulError  - MCI error code
  2051.  *
  2052.  * Return       : none.
  2053.  *
  2054.  ******************************************************************************/
  2055. VOID AudioError ( ULONG ulError )
  2056. {
  2057.    CHAR  szErrorMessage [ERROR_LENGTH];
  2058.  
  2059.  
  2060.    mciGetErrorString ( ulError, (PSZ)szErrorMessage, ERROR_LENGTH );
  2061.  
  2062.    WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szErrorMessage, szErrorMsgTitle,
  2063.                                            0, MB_OK | MB_ERROR | MB_MOVEABLE );
  2064. }
  2065.  
  2066.  
  2067. /******************************************************************************
  2068.  * Name         : LoadTextFile
  2069.  *
  2070.  * Description  : This function will load the selected text or caption file
  2071.  *                for processing.
  2072.  *
  2073.  * Parameters   : szFilename - selected text file
  2074.  *
  2075.  * Return       : apiret     - if an error occured.
  2076.  *
  2077.  ******************************************************************************/
  2078. APIRET LoadTextFile ( CHAR szFilename[] )
  2079. {
  2080.    APIRET    apiret;         /* DOS return code                               */
  2081.    HFILE     hfile;          /* Text file handle                              */
  2082.    ULONG     ulAction;       /* Parameter returned by various DOS API func.   */
  2083.    ULONG     ulFileSize;     /* Expected file size                            */
  2084.    PLINEDATA pld;            /* Used in building the Line Data Table          */
  2085.    PSZ       psz;
  2086.    PLINEDATA pldIn, pldOut;
  2087.    PVOID     pvTextBackup;   /* Temporary holding area for pvText             */
  2088.    MRESULT   mresult;        /* Data returned for queries of slider arm info. */
  2089.    SHORT     sArmPosition;   /* Audio slider arm position                     */
  2090.  
  2091.  
  2092. /*----------------------- Open the text file ---------------------------------*/
  2093.  
  2094.    apiret = DosOpen ( (PSZ) szFilename, &hfile, &ulAction, 0,
  2095.                       FILE_NORMAL | FILE_READONLY, FILE_OPEN,
  2096.                       OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE, NULL );
  2097.  
  2098.    if ( apiret ) return apiret;
  2099.  
  2100.  
  2101. /*------------ Read the entire file into a memory area -----------------------*/
  2102.  
  2103.    pvTextBackup = pvText;                   /* Save the currently-loaded text */
  2104.                                             /* data in case the open fails.   */
  2105.  
  2106.    DosSetFilePtr( hfile, 0, FILE_END, &ulFileSize );/*Determine file size and */
  2107.    apiret = DosAllocMem(&pvText, ulFileSize, fALLOC);/* allocate memory for it*/
  2108.  
  2109.    if ( apiret)                 /*----------- Open failed --------------------*/
  2110.    {                            /*                                            */
  2111.       DosClose ( hfile );       /* Return the error code to the user and      */
  2112.       pvText = pvTextBackup;    /* restore the previous text data pointer.    */
  2113.       return apiret;            /*--------------------------------------------*/
  2114.    }
  2115.  
  2116.    DosSetFilePtr ( hfile, 0, FILE_BEGIN, &ulAction );  /* Read the file image */
  2117.    apiret = DosRead( hfile, pvText, ulFileSize, &ulAction );/* into the buffer*/
  2118.    DosClose ( hfile );
  2119.    if ( ! apiret && ( ulFileSize != ulAction ) ) apiret = ERROR_UNEXPECTED_EOF;
  2120.  
  2121.    if ( apiret )                /*----------- Read failed --------------------*/
  2122.    {                            /*                                            */
  2123.       DosFreeMem ( pvText );    /* Return the error code to the user and      */
  2124.       pvText = pvTextBackup;    /* restore the previous text data pointer.    */
  2125.       return apiret;            /*--------------------------------------------*/
  2126.    }
  2127.  
  2128.  
  2129. /*----------------------------------------------------------------------------*/
  2130. /*                                                                            */
  2131. /* At this point, the existing text or caption file must be unloaded.  Set the*/
  2132. /* dialog box controls to reflect this state, just in case something goes     */
  2133. /* wrong while setting up the new text or caption file.                       */
  2134. /*                                                                            */
  2135. /*----------------------------------------------------------------------------*/
  2136.  
  2137.    DosFreeMem ( pvTextBackup );          /* Free previously-loaded text data. */
  2138.  
  2139.    bTextLoaded     = FALSE;              /* Set internal switches             */
  2140.    bCaptionsLoaded = FALSE;
  2141.    bUnsavedChanges = FALSE;
  2142.    szTextFile[0] = 0;
  2143.    szCaptionFile[0] = 0;
  2144.  
  2145.    GpiErase ( hpsText );                 /* Blankout text window              */
  2146.    WinInvalidateRect ( hwndText, NULL, FALSE );
  2147.  
  2148.    WinSendMsg ( hwndMenu, MM_SETITEMATTR,/* Disable Save and Save as... menus */
  2149.                 MPFROM2SHORT ( IDM_SAVE, TRUE ),
  2150.                 MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED ) );
  2151.    WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2152.                 MPFROM2SHORT ( IDM_SAVEAS, TRUE ),
  2153.                 MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED ) );
  2154.  
  2155.    WinEnableWindow  ( WinWindowFromID ( hwndMainDlg, ID_SET_TIMING ), FALSE );
  2156.    WinEnableWindow  ( WinWindowFromID ( hwndMainDlg, ID_PLAY       ), FALSE );
  2157.  
  2158.  
  2159. /*----------------------------------------------------------------------------*/
  2160. /*                                                                            */
  2161. /*  Convert the file image to a series of NULL-terminated strings by changing */
  2162. /*  all carriage-returns to NULLs.  Build the Line Data Table with an entry   */
  2163. /*  pointing to each string.  When done, usLineCount will contain a count of  */
  2164. /*  the entries used in the Line Data Table.                                  */
  2165. /*                                                                            */
  2166. /*----------------------------------------------------------------------------*/
  2167.  
  2168.    pld = (PLINEDATA) pvLinedataTable;
  2169.    psz = (PSZ) pvText;
  2170.  
  2171.    for ( usLineCount = 1; usLineCount < MAX_TEXT_LINES; usLineCount++ )
  2172.    {
  2173.       pld->szText = psz;
  2174.       pld->ulTime = LINE_NOT_TIMED;
  2175.       psz = (PSZ) memchr ( pvText, CHAR_RETURN, (size_t) ulFileSize );
  2176.       if ( psz == NULL ) break;
  2177.       *psz = CHAR_NULL;
  2178.       psz += 2;
  2179.       if ( *psz == CHAR_EOF ) break;
  2180.       pld++;
  2181.    }
  2182.    if ( usLineCount == MAX_TEXT_LINES ) return (APIRET) ERROR_TOO_MANY_LINES;
  2183.  
  2184.    bTextLoaded = TRUE;
  2185.  
  2186.  
  2187. /*------- Put the length of each string in the Line Data Table ---------------*/
  2188.  
  2189.    pld = (PLINEDATA) pvLinedataTable;
  2190.    for ( usDisplayLine = 0; usDisplayLine < usLineCount; usDisplayLine++ )
  2191.    {
  2192.       pld->lTextLen = (LONG) strlen ( pld->szText );
  2193.       pld++;
  2194.    }
  2195.  
  2196.  
  2197. /*----------------------------------------------------------------------------*/
  2198. /*                                                                            */
  2199. /* If the user has loaded a text file that is already in Caption format,      */
  2200. /* build the Line Data Table from the information already present in the file.*/
  2201. /* If the file is plain text, mark the first line for immediate display.      */
  2202. /*                                                                            */
  2203. /*----------------------------------------------------------------------------*/
  2204.  
  2205.    pldOut = (PLINEDATA) pvLinedataTable;
  2206.  
  2207.    if ( ! strcmp ( (PCHAR) pldOut->szText, szCC_FILE ) )
  2208.    {
  2209.       bCaptionsLoaded = TRUE;
  2210.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVE,   TRUE ),
  2211.                                              MPFROM2SHORT ( MIA_DISABLED, 0 ) );
  2212.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVEAS, TRUE ),
  2213.                                              MPFROM2SHORT ( MIA_DISABLED, 0 ) );
  2214.       strcpy ( szCaptionFile, szFilename );
  2215.       pldIn = pldOut + 1;
  2216.       usLineCount--;
  2217.       for ( usDisplayLine = 0; usDisplayLine< usLineCount; usDisplayLine++ )
  2218.       {
  2219.          *pldOut = *pldIn;
  2220.          pldOut->szText[8] = CHAR_NULL;
  2221.          pldOut->ulTime    = (ULONG) atol ( (PCHAR) pldOut->szText );
  2222.          pldOut->szText   += 9;
  2223.          pldOut->lTextLen -= 9;
  2224.          pldIn++;
  2225.          pldOut++;
  2226.       }
  2227.    }
  2228.    else
  2229.    {
  2230.       bCaptionsLoaded = FALSE;
  2231.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVE,   TRUE ),
  2232.                                  MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED ) );
  2233.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVEAS, TRUE ),
  2234.                                  MPFROM2SHORT ( MIA_DISABLED, 0            ) );
  2235.       strcpy ( szTextFile, szFilename );
  2236.       szCaptionFile[0] = 0;
  2237.       pldOut = (PLINEDATA) pvLinedataTable;/*---------------------------------*/
  2238.       pldOut[0].ulTime = 0;                /*Mark the first line for immediate*/
  2239.                                            /*display                          */
  2240.    }                                       /*---------------------------------*/
  2241.  
  2242.    /*-------------------------------------------------------------------------*/
  2243.    /* Now set the initial caption position.  If there is an audio file loaded,*/
  2244.    /* set the position according to the position of the audio file.  If there */
  2245.    /* is no audio file loaded, just display the first line of text at the     */
  2246.    /* bottom of the text window                                               */
  2247.    /*-------------------------------------------------------------------------*/
  2248.  
  2249.    if ( iState != ST_CLOSED )
  2250.    {
  2251.       mresult =
  2252.           WinSendMsg( hwndAudioSlider, SLM_QUERYSLIDERINFO,
  2253.                       MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_RANGEVALUE), 0 );
  2254.       sArmPosition = SHORT1FROMMP ( (MPARAM) mresult );
  2255.       PositionCaptions ( sArmPosition );
  2256.    }
  2257.    else
  2258.    {
  2259.       usDisplayLine = 0;                           /*-------------------------*/
  2260.       DisplayTextLine();                           /* Display the first line  */
  2261.       WinInvalidateRect ( hwndText, NULL, FALSE ); /*-------------------------*/
  2262.       usNextline = 1;
  2263.    }
  2264.  
  2265.  
  2266. /*--- Set the Start Timing button, the Play button ---------------------------*/
  2267.  
  2268.    if ( bAudioLoaded )
  2269.    {
  2270.       WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_SET_TIMING ), TRUE );
  2271.    }
  2272.  
  2273.    if ( bCaptionsLoaded && bAudioLoaded )
  2274.       WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_PLAY ), TRUE );
  2275.  
  2276.    return 0;
  2277. }
  2278.  
  2279.  
  2280. /******************************************************************************
  2281.  * Name         : PositionCaptions
  2282.  *
  2283.  * Description  : This function will position the captions in the caption
  2284.  *                window according to the position of the audio slider.
  2285.  *
  2286.  * Parameters   : aArmPos   -  audio slider arm position
  2287.  *
  2288.  * Return       : none.
  2289.  *
  2290.  ******************************************************************************/
  2291. VOID PositionCaptions ( SHORT sArmPos )
  2292. {
  2293.    PLINEDATA pld;
  2294.    ULONG     ulAudioPos;                        /* Audio position in MM units */
  2295.    SHORT     sLineIndex;
  2296.  
  2297.  
  2298.    if ( ! bTextLoaded ) return;
  2299.                                                   /*--------------------------*/
  2300.    WinStopTimer ( hab, hwndText, CC_TIMER_ID );   /*   Be sure to stop any    */
  2301.    usNextlineReq = 0;                             /*   scrolling in progress. */
  2302.    lScrollOffset = 0;                             /*--------------------------*/
  2303.  
  2304.    ulAudioPos = (ULONG) ( ulAudioLength * sArmPos / ( sAudioArmRange - 1 ) );
  2305.    pld        = (PLINEDATA) pvLinedataTable;
  2306.  
  2307.    for ( sLineIndex = 0; sLineIndex < (SHORT) usLineCount; sLineIndex++ )
  2308.    {
  2309.        if ( pld->ulTime == ulAudioPos ) break;  /*---------------------------*/
  2310.        if ( pld->ulTime > ulAudioPos )          /* Scan the Line Data Table  */
  2311.        {                                        /* until we reach a line     */
  2312.           sLineIndex--;                         /* to be shown at or later   */
  2313.           if ( sLineIndex < 0 ) sLineIndex = 0; /* than the current audio    */
  2314.           break;                                /* position, or until we run */
  2315.        }                                        /* off the end of the table. */
  2316.        pld++;                                   /*---------------------------*/
  2317.    }
  2318.  
  2319.    if ( sLineIndex == (SHORT) usLineCount ) sLineIndex--;
  2320.  
  2321.    if ( usDisplayLine != (USHORT) sLineIndex )
  2322.    {
  2323.       usDisplayLine     = (USHORT) sLineIndex;      /*------------------------*/
  2324.       DisplayTextLine   ();                         /*      Display the text  */
  2325.       WinInvalidateRect ( hwndText, NULL, FALSE );  /*------------------------*/
  2326.       usNextline        = usDisplayLine + 1;
  2327.    }
  2328. }
  2329.  
  2330.  
  2331. /******************************************************************************
  2332.  * Name         : DisplayTextLine
  2333.  *
  2334.  * Description  : This function will write a line of text to the backup bitmap
  2335.  *                of the text window to display it.
  2336.  *
  2337.  * Parameters   : none.
  2338.  *
  2339.  * Return       : none.
  2340.  *
  2341.  ******************************************************************************/
  2342. static VOID DisplayTextLine ( void )
  2343. {
  2344.    PLINEDATA pld;
  2345.    POINTL    ptl;
  2346.    USHORT    usTestLine;
  2347.    LONG      lLineCount;
  2348.    SHORT     sPosition;
  2349.  
  2350. /*-- Erase the pres. space and point ptl to the left end of the bottom line --*/
  2351.  
  2352.    GpiErase ( hpsText );
  2353.    pld        = (PLINEDATA) pvLinedataTable + usDisplayLine;
  2354.    ptl.x      = CC_XMARGIN;
  2355.    ptl.y      = lLastLineY;
  2356.    usTestLine = usDisplayLine;
  2357.  
  2358.  
  2359. /*----------------------------------------------------------------------------*/
  2360. /* Write lines from bottom to top until we have filled the window or run out  */
  2361. /* of lines.                                                                  */
  2362. /*----------------------------------------------------------------------------*/
  2363.  
  2364.    for ( lLineCount = 0; lLineCount < lDisplayLines; lLineCount++ )
  2365.    {
  2366.       if ( usTestLine < usLineCount )
  2367.          GpiCharStringAt ( hpsText, &ptl, pld->lTextLen, (PCH) pld->szText );
  2368.       if ( usTestLine == 0 ) break;
  2369.       ptl.y += lLineSpacing;
  2370.       pld--;
  2371.       usTestLine--;
  2372.    }
  2373. }
  2374.  
  2375.  
  2376. /******************************************************************************
  2377.  * Name         : SaveChanges
  2378.  *
  2379.  * Description  : This function will ask the user if he wants to save the
  2380.  *                changes made to the text or caption file.
  2381.  *
  2382.  * Parameters   : flStyle  - buttons style flags for the message box.
  2383.  *
  2384.  * Return       : usReturn - result of the WinMessageBox call.
  2385.  *
  2386.  ******************************************************************************/
  2387. USHORT SaveChanges ( ULONG flStyle )
  2388. {
  2389.    USHORT usReturn;
  2390.    PSZ    psz, pszSlash;
  2391.    CHAR   szMessage[100];
  2392.  
  2393.  
  2394.    WinLoadString ( hab, 0, STRID_SAVECHANGES_MESSAGE, 100,         szMessage );
  2395.  
  2396.    usReturn = WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szMessage,
  2397.                               szErrorMsgTitle, 0,
  2398.                               flStyle | MB_QUERY | MB_MOVEABLE);
  2399.  
  2400.  
  2401. /*---- If the user asks to save the file, give him a Save as dialog box ------*/
  2402.  
  2403.    if ( usReturn == MBID_YES )
  2404.    {
  2405.       if ( szCaptionFile [0] )
  2406.          FormatFname ( fdgSaveAs.szFullFile, szCaptionFile );
  2407.       else
  2408.       {
  2409.          FormatFname ( fdgSaveAs.szFullFile, szTextFile );
  2410.          psz      = (PSZ) strrchr ( fdgSaveAs.szFullFile, '.' );
  2411.          pszSlash = (PSZ) strrchr ( fdgSaveAs.szFullFile, '\\' );
  2412.          if ( pszSlash < psz )  strcpy  ( (char *)psz, "._CC" );
  2413.       }
  2414.  
  2415.       usFiledlgHelpRes = PANEL_FILEDLG_SAVEAS;
  2416.       if ( DisplaySaveasDlg(IDM_SAVE) == DID_CANCEL )
  2417.          usReturn = MBID_CANCEL;
  2418.    }
  2419.  
  2420.    return usReturn;
  2421. }
  2422.  
  2423.  
  2424. /******************************************************************************
  2425.  * Name         : CheckForTiming
  2426.  *
  2427.  * Description  : This function will check for untimed lines in the text file.
  2428.  *                This function is called just before a caption file is to be
  2429.  *                saved.  It scans the Line Data Table looking for lines which
  2430.  *                have been left untimed.  If an untimed line is found, the
  2431.  *                function then asks the user if he still wants to save.
  2432.  *
  2433.  * Parameters   : none.
  2434.  *
  2435.  * Return       : TRUE   -  if the file is to be saved (or if there are no
  2436.  *                          untimed lines).
  2437.  *                FALSE  -  if the user decides not to save the file.
  2438.  *
  2439.  ******************************************************************************/
  2440. BOOL CheckForTiming ( void )
  2441. {
  2442.    PLINEDATA pld;
  2443.    USHORT    usLineIndex, usReturn;
  2444.    CHAR      szError[ERROR_LENGTH];
  2445.  
  2446.    pld = (PLINEDATA) pvLinedataTable;
  2447.    for ( usLineIndex = 0; usLineIndex < usLineCount; usLineIndex++ )
  2448.    {
  2449.       if ( pld->ulTime == LINE_NOT_TIMED )
  2450.       {
  2451.          WinLoadString ( hab, 0, STRID_UNTIMED_MESSAGE, ERROR_LENGTH, szError );
  2452.  
  2453.          usReturn = WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError,
  2454.                                     szErrorMsgTitle, 0,
  2455.                                     MB_YESNO | MB_QUERY | MB_MOVEABLE);
  2456.          if ( usReturn == MBID_YES )
  2457.             return TRUE;
  2458.          else
  2459.             return FALSE;
  2460.       }
  2461.       pld++;
  2462.    }
  2463.  
  2464.    return TRUE;
  2465. }
  2466.  
  2467.  
  2468. /******************************************************************************
  2469.  * Name         : SaveCaptionFile
  2470.  *
  2471.  * Description  : This function will save the caption file that is currently
  2472.  *                loaded.
  2473.  *
  2474.  * Parameters   : szFilename  - use this file name to save
  2475.  *                sMenuItem   - menu selected like "Save" or "Save as"
  2476.  *
  2477.  * Return       : apiret   -  function return code.
  2478.  *
  2479.  ******************************************************************************/
  2480. APIRET SaveCaptionFile ( CHAR szFilename[], SHORT sMenuItem )
  2481. {
  2482.    HFILE      hfile;
  2483.    ULONG      ulAction;
  2484.    USHORT     usResponse;
  2485.    PLINEDATA  pld;
  2486.    USHORT     usLineIndex;
  2487.    CHAR       szOutput[MAX_OUTPUT_LENGTH];
  2488.    BOOL       bTruncated;
  2489.    APIRET     apiret;
  2490.    CHAR       szError[ERROR_LENGTH];
  2491.    USHORT     i;
  2492.  
  2493. /*----------------------------------------------------------------------------*/
  2494. /*                                                                            */
  2495. /*  Try to open the Caption File.  If the user is trying to "Save as..." a    */
  2496. /*  file which already exists, issue a warning and ask him if he wants to     */
  2497. /*  overwrite the file.                                                       */
  2498. /*                                                                            */
  2499. /*----------------------------------------------------------------------------*/
  2500.  
  2501.    apiret = DosOpen ( (PSZ) szFilename, &hfile, &ulAction, 0,
  2502.                       FILE_NORMAL, FILE_CREATE,
  2503.                       OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL );
  2504.  
  2505.    if ( ( apiret == ERROR_OPEN_FAILED ) &&
  2506.         ( sMenuItem == IDM_SAVE ) )
  2507.       apiret = DosOpen( (PSZ) szFilename, &hfile, &ulAction, 0,
  2508.                         FILE_NORMAL, FILE_TRUNCATE,
  2509.                         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL);
  2510.  
  2511.                                                  /* Trap overwrites for the   */
  2512.    if ( apiret == ERROR_OPEN_FAILED )            /* SAVE AS... menu item      */
  2513.    {
  2514.       WinLoadString ( hab, 0, STRID_OVERWRITE_QUERY, ERROR_LENGTH, szError );
  2515.       usResponse =
  2516.         WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szFilename,
  2517.                                    0, MB_OKCANCEL | MB_QUERY | MB_MOVEABLE);
  2518.  
  2519.       if ( usResponse == MBID_CANCEL )
  2520.       {
  2521.         /*
  2522.          * If the user select's cancel, that means he wants to retry saving
  2523.          * the file using a different name.  So, go thru the same logic
  2524.          * again.
  2525.          */
  2526.         DisplaySaveasDlg(sMenuItem);
  2527.         return apiret;
  2528.       }
  2529.       /*
  2530.        * The user's response was OK to the "overwrite" warning message.
  2531.        * Go ahead and overwrite the file.
  2532.        */
  2533.       else
  2534.       {
  2535.          apiret =
  2536.            DosOpen( (PSZ) szFilename, &hfile, &ulAction, 0,
  2537.                     FILE_NORMAL, FILE_TRUNCATE,
  2538.                     OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL );
  2539.       }
  2540.    }
  2541.  
  2542.    if ( apiret )
  2543.    {
  2544.       DisplayDosError ( szErrorMsgTitle, apiret );
  2545.       return apiret;
  2546.    }
  2547.  
  2548.  
  2549. /*---------------- Write the Caption data to the file ------------------------*/
  2550.  
  2551.    bTruncated = FALSE;
  2552.  
  2553.    apiret = WriteLine ( hfile, (PSZ) szCC_FILE );
  2554.    if ( !apiret )
  2555.    {
  2556.       pld = (PLINEDATA) pvLinedataTable;
  2557.       for ( usLineIndex = 0; usLineIndex < usLineCount; usLineIndex++ )
  2558.       {
  2559.          sprintf ( szOutput, "%08lu ", pld->ulTime );
  2560.          if ( ( pld->lTextLen + 10 ) > MAX_OUTPUT_LENGTH ) bTruncated = TRUE;
  2561.          strncat(szOutput,(char *)pld->szText,(size_t)(MAX_OUTPUT_LENGTH - 10));
  2562.          apiret = WriteLine ( hfile, (PSZ) szOutput );
  2563.          if ( apiret ) break;
  2564.          pld++;
  2565.       }
  2566.       if ( ! apiret )
  2567.       {
  2568.          apiret = DosWrite ( hfile, &cEOF, 1, &ulAction );
  2569.          if ( ! apiret && ! ulAction ) apiret = ERROR_DISK_FULL;
  2570.          if ( apiret ) DisplayDosError ( szErrorMsgTitle, apiret );
  2571.       }
  2572.    }
  2573.    DosClose ( hfile );
  2574.    if ( bTruncated )
  2575.    {
  2576.       WinLoadString ( hab, 0, STRID_TRUNCATE_WARNING, ERROR_LENGTH, szError );
  2577.       WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szFilename, 0,
  2578.                                     MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  2579.    }
  2580.    if ( ! apiret ) bUnsavedChanges = FALSE;
  2581.    return apiret;
  2582. }
  2583.  
  2584.  
  2585. /******************************************************************************
  2586.  * Name         : WriteLine
  2587.  *
  2588.  * Description  : This function will write a single line to the caption file.
  2589.  *                loaded.
  2590.  *
  2591.  * Parameters   : hfile  - Handle of output file
  2592.  *                psz    - Pointer to a NULL-terminated string to write to the
  2593.  *                         file.
  2594.  *
  2595.  * Return       : apiret -  function return code.
  2596.  *
  2597.  ******************************************************************************/
  2598. APIRET WriteLine ( HFILE hfile, PSZ psz )
  2599. {
  2600.    APIRET apiret;
  2601.    ULONG  ulBytesReq;
  2602.    ULONG  ulBytesWritten;
  2603.    CHAR   acNewline[] = { CHAR_RETURN, CHAR_LINEFEED };
  2604.  
  2605.  
  2606.    ulBytesReq = (ULONG) strlen ( (char *)psz );
  2607.    apiret = DosWrite ( hfile, psz, ulBytesReq, &ulBytesWritten );
  2608.    if ( ! apiret && ( ulBytesWritten < ulBytesReq ) ) apiret = ERROR_DISK_FULL;
  2609.    if ( ! apiret )
  2610.    {
  2611.       apiret = DosWrite ( hfile, acNewline, 2, &ulBytesWritten );
  2612.       if ( ! apiret && ( ulBytesWritten < 2 ) ) apiret = ERROR_DISK_FULL;
  2613.    }
  2614.    if ( apiret ) DisplayDosError ( szErrorMsgTitle, apiret );
  2615.    return apiret;
  2616. }
  2617.  
  2618.  
  2619. /******************************************************************************
  2620.  * Name         : DisplayDosError
  2621.  *
  2622.  * Description  : This function will display a Dos of local file error.
  2623.  *
  2624.  * Parameters   : szTitle - Error message-box title.
  2625.  *                apiret  - DOS or local error code.
  2626.  *
  2627.  * Return       : none.
  2628.  *
  2629.  ******************************************************************************/
  2630. VOID DisplayDosError ( CHAR szTitle[], APIRET apiret )
  2631. {
  2632.    CHAR  szError[ERROR_LENGTH];
  2633.    CHAR  szFormat[ERROR_LENGTH];
  2634.  
  2635.  
  2636.    switch ( apiret )
  2637.    {
  2638.       case ERROR_TEXT_FILE_FORMAT:
  2639.          WinLoadString( hab, 0, STRID_TEXT_FILE_FORMAT, ERROR_LENGTH, szError );
  2640.          break;
  2641.  
  2642.       case ERROR_TOO_MANY_LINES:
  2643.          WinLoadString ( hab, 0, STRID_TOO_MANY_LINES, ERROR_LENGTH, szError );
  2644.          break;
  2645.  
  2646.       case ERROR_UNEXPECTED_EOF:
  2647.          WinLoadString ( hab, 0, STRID_UNEXPECTED_EOF, ERROR_LENGTH, szError );
  2648.          break;
  2649.  
  2650.       case ERROR_DISK_FULL:
  2651.          WinLoadString ( hab, 0, STRID_DISK_FULL, ERROR_LENGTH, szError );
  2652.          break;
  2653.  
  2654.       case ERROR_CANNOT_FIND_TEXTFILE:
  2655.          WinLoadString ( hab, 0, STRID_CANNOT_FIND_TEXTFILE, ERROR_LENGTH, szError );
  2656.          break;
  2657.  
  2658.       default:
  2659.          WinLoadString(hab, 0, STRID_GENERIC_DOS_ERROR, ERROR_LENGTH, szError );
  2660.    }
  2661.  
  2662.    WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szTitle, 0,
  2663.                                                MB_OK | MB_ERROR | MB_MOVEABLE);
  2664. }
  2665.  
  2666.  
  2667. /******************************************************************************
  2668.  * Name         : ResizeTextWindow
  2669.  *
  2670.  * Description  : This function will resize an existing text window to a
  2671.  *                different number of lines selected. Also adjust the main
  2672.  *                dialog window according to the text window size.
  2673.  *
  2674.  * Parameters   : lNewDisplayLines  - Number of lines desired.
  2675.  *
  2676.  * Return       : none.
  2677.  *
  2678.  ******************************************************************************/
  2679. static VOID ResizeTextWindow ( LONG lNewDisplayLines )
  2680. {
  2681.    LONG  lWidth;
  2682.    LONG  lHeight;
  2683.    LONG  lX;
  2684.    LONG  lY;
  2685.    SWP   swpFrame;
  2686.    SWP   swpDialog;
  2687.    SWP   swpText;
  2688.  
  2689. /*-------- Uncheck the menu item for previous display lines ------------------*/
  2690.  
  2691.    switch ( lDisplayLines )
  2692.    {
  2693.       case 2: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2694.                                      MPFROM2SHORT ( IDM_2_LINES, TRUE ),
  2695.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2696.               break;
  2697.  
  2698.       case 3: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2699.                                      MPFROM2SHORT ( IDM_3_LINES, TRUE ),
  2700.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2701.               break;
  2702.  
  2703.       case 4: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2704.                                      MPFROM2SHORT ( IDM_4_LINES, TRUE ),
  2705.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2706.               break;
  2707.  
  2708.       case 5: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2709.                                      MPFROM2SHORT ( IDM_5_LINES, TRUE ),
  2710.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2711.               break;
  2712.  
  2713.       case 6: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2714.                                      MPFROM2SHORT ( IDM_6_LINES, TRUE ),
  2715.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2716.    }
  2717.  
  2718.  
  2719. /*-------- Check the menu item for the new display line count ----------------*/
  2720.  
  2721.    switch ( lNewDisplayLines )
  2722.    {
  2723.       case 2: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2724.                                MPFROM2SHORT ( IDM_2_LINES, TRUE ),
  2725.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2726.               break;
  2727.  
  2728.       case 3: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2729.                                MPFROM2SHORT ( IDM_3_LINES, TRUE ),
  2730.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2731.               break;
  2732.  
  2733.       case 4: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2734.                                MPFROM2SHORT ( IDM_4_LINES, TRUE ),
  2735.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2736.               break;
  2737.  
  2738.       case 5: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2739.                                MPFROM2SHORT ( IDM_5_LINES, TRUE ),
  2740.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2741.               break;
  2742.  
  2743.       case 6: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2744.                                MPFROM2SHORT ( IDM_6_LINES, TRUE ),
  2745.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2746.    }
  2747.  
  2748.    lDisplayLines = lNewDisplayLines;
  2749.  
  2750. /*---------------------- Resize the Window -----------------------------------*/
  2751. /*                                                                            */
  2752. /*  (1) Hide the Text window, so we don't get a WM_PAINT message while the    */
  2753. /*      backup bitmap is destroyed.                                           */
  2754. /*                                                                            */
  2755. /*  (2) Delete the present backup bitmap.                                     */
  2756. /*                                                                            */
  2757. /*  (3) Create a new backup bitmap having the desired dimensions.             */
  2758. /*                                                                            */
  2759. /*  (4) Calculate the new Text Window size.                                   */
  2760. /*                                                                            */
  2761. /*  (5) Calculate the new Main Window size.                                   */
  2762. /*                                                                            */
  2763. /*  (6) Show the new text window.                                             */
  2764. /*                                                                            */
  2765. /*----------------------------------------------------------------------------*/
  2766.  
  2767.    WinSetWindowPos( hwndText, 0, 0, 0, 0, 0, SWP_HIDE );/*(1) Hide text window*/
  2768.  
  2769.    GpiDestroyPS( hpsText );  /*-----------------------------------------------*/
  2770.    DevCloseDC  ( hdcText );  /*(2)Get rid of the old text window backup bitmap*/
  2771.    GpiDeleteBitmap( hbmText);/*-----------------------------------------------*/
  2772.  
  2773.    CreateTextBitmap ();   /* (3) Create a backup bitmap in the new dimensions */
  2774.  
  2775.    lWidth  = rclMain.xRight - 10;
  2776.    lHeight   = ( 2 * lTitleY + rclTextClient.yTop );
  2777.    lX = 5;
  2778.    lY = ( rclMain.yTop - (rclMain.yTop / 5) ) ;
  2779.  
  2780.    WinSetWindowPos( hwndText, 0, lX, lY, lWidth, lHeight, /*(4) Show new text */
  2781.                           SWP_SHOW | SWP_MOVE | SWP_SIZE );/*     window.  */
  2782.  
  2783.    WinQueryWindowPos   ( hwndMainFrame, &swpFrame ) ;      /* (5)             */
  2784.  
  2785.    /*
  2786.     * Query the window size and position of the Dialog window.
  2787.     */
  2788.    WinQueryWindowPos( hwndMainDlg, &swpDialog ) ;
  2789.    WinQueryWindowPos( hwndText, &swpText ) ;
  2790.  
  2791.    if ( lcyDialog > lHeight )
  2792.       swpDialog.cy -=  lcyDialog - lHeight;
  2793.    else
  2794.       swpDialog.cy +=  lHeight - lcyDialog;
  2795.  
  2796.    lcyDialog = lHeight;
  2797.  
  2798.    /*
  2799.     * Set the positioning of the Dialog window.
  2800.     */
  2801.    WinSetWindowPos(
  2802.          hwndMainDlg,                    /* Dialog window handle              */
  2803.          0L,                             /* Place hwnd on top of all siblings */
  2804.          0L,                             /* Window position, x coordinate     */
  2805.          0L,                             /* Window position, y coordinate     */
  2806.          swpDialog.cx,                   /* New window size                   */
  2807.          swpDialog.cy,                   /* New window size                   */
  2808.          SWP_SIZE ) ;                    /* Window positioning options        */
  2809.  
  2810.    WinUpdateWindow(hwndMainDlg);
  2811.  
  2812.    if ( bTextLoaded ) DisplayTextLine();
  2813.  
  2814.    WinInvalidateRect ( hwndText, 0, FALSE );
  2815. }
  2816.  
  2817.  
  2818. /******************************************************************************
  2819.  * Name         : CreateTextBitmap
  2820.  *
  2821.  * Description  : This function will create a backup bitmap for the text window.
  2822.  *
  2823.  * Parameters   : none.
  2824.  *
  2825.  * Return       : none.
  2826.  *
  2827.  ******************************************************************************/
  2828. VOID CreateTextBitmap ( void )
  2829. {
  2830.    FONTMETRICS       fmText;
  2831.    LONG              lModulo;
  2832.    SIZEL             sizelText;
  2833.    BITMAPINFOHEADER2 bmh2;
  2834.  
  2835.  
  2836. /*--- Open a memory device context and create a Micro presentation space -----*/
  2837.  
  2838.    hdcText          = DevOpenDC ( hab, OD_MEMORY, "*", 0, NULL, 0 );
  2839.  
  2840.    sizelText.cx     = 0;
  2841.    sizelText.cy     = 0;
  2842.    hpsText          = GpiCreatePS ( hab, hdcText, &sizelText,
  2843.                             PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  2844.  
  2845.  
  2846. /*------------------- Calculate bitmap height --------------------------------*/
  2847. /*                                                                            */
  2848. /*  The height of the caption window and the line spacing within the window   */
  2849. /*  both depend on the height of the font being used.  (1) We will use the    */
  2850. /*  default font for the presentation space.  (2) The line spacing (in pels)  */
  2851. /*  will be AT LEAST:                                                         */
  2852. /*                                                                            */
  2853. /*      ( Max Baseline Extent ) + ( External Leading ) + ( Scroll Increment ) */
  2854. /*                                                                            */
  2855. /*  (3) There is one further condition: the line spacing must be an integer   */
  2856. /*  multiple of the scroll increment.  If necessary, increase the above line  */
  2857. /*  spacing so that this condition is met.                                    */
  2858. /*                                                                            */
  2859. /*----------------------------------------------------------------------------*/
  2860.  
  2861.    GpiQueryFontMetrics ( hpsText, sizeof(fmText), &fmText );/*(1) default font*/
  2862.  
  2863.    lLineSpacing  = fmText.lMaxBaselineExt          /* (2) Lower limit of line */
  2864.                  + fmText.lExternalLeading         /*     spacing.            */
  2865.                  + CC_SCROLL_INC;
  2866.  
  2867.    lModulo = lLineSpacing % CC_SCROLL_INC;
  2868.    if ( lModulo )                                /* (3) Adjust spacing to int */
  2869.       lLineSpacing += CC_SCROLL_INC - lModulo;   /*     mult of scroll incr.  */
  2870.  
  2871.    rclTextClient.yTop =
  2872.           lDisplayLines * lLineSpacing;          /* Now calculate height and  */
  2873.    lLastLineY = CC_SCROLL_INC + fmText.lMaxDescender;/*position of last line. */
  2874.  
  2875.  
  2876. /*-- Create a monochrome bitmap having the dimensions we just calculated -----*/
  2877.  
  2878.    bmh2.cbFix             = sizeof (BITMAPINFOHEADER2);
  2879.    bmh2.cx                = CC_WIDTH;
  2880.    bmh2.cy                = rclTextClient.yTop;
  2881.    bmh2.cPlanes           = 1;
  2882.    bmh2.cBitCount         = 1;                 /* This is a monochrome bitmap */
  2883.    bmh2.ulCompression     = BCA_UNCOMP;
  2884.    bmh2.cbImage           = 0;
  2885.    bmh2.cxResolution      = 30000;
  2886.    bmh2.cyResolution      = 30000;
  2887.    bmh2.cclrUsed          = 2;
  2888.    bmh2.cclrImportant     = 2;
  2889.    bmh2.usUnits           = BRU_METRIC;
  2890.    bmh2.usReserved        = 0;
  2891.    bmh2.usRecording       = BRA_BOTTOMUP;
  2892.    bmh2.usRendering       = BRH_NOTHALFTONED;
  2893.    bmh2.cSize1            = 0;
  2894.    bmh2.cSize2            = 0;
  2895.    bmh2.ulColorEncoding   = BCE_RGB;
  2896.    bmh2.ulIdentifier      = 0;
  2897.    hbmText                = GpiCreateBitmap ( hpsText, &bmh2, 0L, 0L, NULL );
  2898.  
  2899.    GpiSetBitmap   ( hpsText, hbmText );  /* Set the bitmap into the pres space*/
  2900.    GpiErase       ( hpsText );           /* Erase the bitmap.                 */
  2901. }
  2902.  
  2903. /******************************************************************************
  2904.  * Name        : ProcuctDlgProc
  2905.  *
  2906.  * Description : This function controls the product information dialog box.
  2907.  *
  2908.  * Parameters  : hwnd - Handle for the Include dialog box.
  2909.  *               msg  - Message received by the dialog box.
  2910.  *               mp1  - Parameter 1 for the just received message.
  2911.  *               mp2  - Parameter 2 for the just received message.
  2912.  *
  2913.  * Return      : 0 or the result of default processing.
  2914.  *
  2915.  ******************************************************************************/
  2916. MRESULT EXPENTRY ProductDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  2917. {
  2918.    switch( msg )
  2919.    {
  2920.      case WM_INITDLG :
  2921.          /*
  2922.           * Add Default Size menu item to system menu of the secondary window.
  2923.           */
  2924.          WinInsertDefaultSize(hwnd, "~DefaultSize");
  2925.  
  2926.          break;
  2927.  
  2928.      case WM_CLOSE :
  2929.          WinDestroySecondaryWindow( hwnd );         /* Close the Dialog box.          */
  2930.          return( 0 );
  2931.          break;
  2932.  
  2933.      case WM_DESTROY:
  2934.          hwndProductInfo = 0;
  2935.          break;
  2936.  
  2937.      case WM_COMMAND :
  2938.          switch( SHORT1FROMMP( mp1 ) )
  2939.          {
  2940.             case DID_OK :
  2941.             case DID_CANCEL:
  2942.                WinDestroySecondaryWindow( hwnd );   /* Close the Dialog box.          */
  2943.                return( (MRESULT)TRUE);
  2944.             break;
  2945.          }  /* End of Command Switch */
  2946.  
  2947.    }  /* End of Switch */
  2948.  
  2949.    return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  2950.  
  2951. } /* End of FileDlgProc */
  2952. /******************************************************************************
  2953.  * Name         : DisplaySaveasDlg
  2954.  *
  2955.  * Description  : This function will display the "Save as" dialog box
  2956.  *
  2957.  * Parameters   : SHORT sMenuItem - menu item that caused this action
  2958.  *
  2959.  * Return       : return code from WinFileDlg
  2960.  *
  2961.  ******************************************************************************/
  2962. LONG DisplaySaveasDlg ( SHORT sMenuItem )
  2963. {
  2964.  
  2965.     /*  (a) Ask the user for a file name.  If he responds favorably:    */
  2966.     /*  (b) Save the file.                                              */
  2967.     /*  (c) Store the name in szCaptionFile.                            */
  2968.     /*  (d) Enable the Save menu item .                                 */
  2969.  
  2970.     if (WinFileDlg(HWND_DESKTOP, hwndMainDlg, &fdgSaveAs))       /* (a) */
  2971.     {
  2972.        if ( fdgSaveAs.lReturn == DID_OK )
  2973.        {
  2974.           if ( iState == ST_PLAYING ) StopPlaying( hwndMainDlg );
  2975.           if (!SaveCaptionFile(fdgSaveAs.szFullFile,sMenuItem))  /* (b) */
  2976.           {
  2977.              strcpy(szCaptionFile,fdgSaveAs.szFullFile);         /* (c) */
  2978.              WinSendMsg ( hwndMenu, MM_SETITEMATTR,              /* (d) */
  2979.                           MPFROM2SHORT ( IDM_SAVE, TRUE ),
  2980.                           MPFROM2SHORT ( MIA_DISABLED, 0 ) );
  2981.           }
  2982.        }
  2983.     }
  2984.     return fdgSaveAs.lReturn;
  2985. }
  2986.