home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mmpm21tk.zip / TK / CAPTION / CAPTION.C next >
C/C++ Source or Header  |  1993-03-20  |  144KB  |  2,987 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. VOID    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.                     if ( apiret = LoadTextFile ( fdgText.szFullFile ) )
  867.                        DisplayDosError ( szErrorMsgTitle, apiret );
  868.                     else
  869.                     {
  870.                        strcpy(szBuffer, szCapFileName);
  871.                        strcat(szBuffer, szNoneFileName);
  872.                        WinSetWindowText( WinWindowFromID( hwnd, ID_CAPTIONTXT),
  873.                                          szBuffer );
  874.  
  875.                        pcTextFile = strrchr( fdgText.szFullFile, '\\' );
  876.                        pcTextFile++;
  877.                        strcpy(szBuffer, szTextFileName);
  878.                        strcat(szBuffer, pcTextFile);
  879.                        WinSetWindowText( WinWindowFromID( hwnd, ID_TEXTTXT),
  880.                                          szBuffer );
  881.                     }
  882.                  }
  883.               break;
  884.  
  885.  
  886.            /*------------ Open Captions... menu item -------------------------*/
  887.            /*                                                                 */
  888.            /* (1) Prompt user to save unsaved changes ( if any ).             */
  889.            /* (2) Set the appropriate help resource for this operation.       */
  890.            /* (3) Reformat the latest caption file name as:  x:\pathname\*.ext*/
  891.            /* (4) Request the user to select a file                           */
  892.            /* (5) If the user selected a file, try to open it.                */
  893.            /*-----------------------------------------------------------------*/
  894.  
  895.            case IDM_OPEN_CAPTIONS:
  896.               if ( bUnsavedChanges )                     /* (1) Unsaved chngs */
  897.                  if ( SaveChanges( MB_YESNOCANCEL ) == MBID_CANCEL ) break;
  898.  
  899.               usFiledlgHelpRes = PANEL_FILEDLG_TEXT;     /* (2) Help resource */
  900.  
  901.               if ( szCaptionFile[0] )                    /* (3) Format filenam*/
  902.                  FormatFname ( fdgText.szFullFile, szCaptionFile );
  903.               else
  904.                  strcpy ( fdgText.szFullFile, "*._CC" );
  905.               fdgText.pszTitle = szCaptionOpen;          /* Open dialog title */
  906.  
  907.               if (WinFileDlg(HWND_DESKTOP, hwnd, &fdgText))/*(4) Ask for name */
  908.                  if ( fdgText.lReturn == DID_OK )          /* (5) Try loading */
  909.                  {
  910.                     if ( iState == ST_PLAYING ) StopPlaying( hwnd );
  911.                     if ( apiret = LoadTextFile ( fdgText.szFullFile ) )
  912.                        DisplayDosError ( szErrorMsgTitle, apiret );
  913.                     else
  914.                     {
  915.                        strcpy(szBuffer, szTextFileName);
  916.                        strcat(szBuffer, szNoneFileName);
  917.                        WinSetWindowText( WinWindowFromID( hwnd, ID_TEXTTXT),
  918.                                          szBuffer );
  919.  
  920.                        pcTextFile = strrchr( fdgText.szFullFile, '\\' );
  921.                        pcTextFile++;
  922.                        strcpy(szBuffer, szCapFileName);
  923.                        strcat(szBuffer, pcTextFile);
  924.                        WinSetWindowText( WinWindowFromID( hwnd, ID_CAPTIONTXT),
  925.                                          szBuffer );
  926.                     }
  927.                  }
  928.               break;
  929.  
  930.  
  931.            /*------------------ Save menu item -------------------------------*/
  932.            /*                                                                 */
  933.            /* (1) Check for any untimed lines. If any are found, ask the user */
  934.            /*     if he is sure he wants to save.  Exit if user answers No.   */
  935.            /* (2) If we successfully got through step one, save the file.     */
  936.            /*---------------------------------------------------------------- */
  937.  
  938.            case IDM_SAVE:
  939.               if ( CheckForTiming() )
  940.                  SaveCaptionFile ( szCaptionFile, IDM_SAVE );
  941.               break;
  942.  
  943.  
  944.            /*--------------- Save as... menu item ---------------------------*/
  945.            /*                                                                */
  946.            /* (1) Check for any untimed lines. If any are found, ask the user*/
  947.            /*     if he is sure he wants to continue. Exit if user answers NO*/
  948.            /*                                                                */
  949.            /* (2) Format a file name to prompt the user.  If there is a      */
  950.            /*     caption file name (in szCaptionFile), use that name as the */
  951.            /*     basis for the prompt.  If there is a text file name, use   */
  952.            /*     that name as the basis.  The prompt will have the format   */
  953.            /*     of:  x:\pathname\*._CC                                     */
  954.            /*                                                                */
  955.            /* (3) Set up the appropriate Help Resource for the file dialog   */
  956.            /*     box.                                                       */
  957.            /*                                                                */
  958.            /* (4) Display the Save As dialog box to the user.                */
  959.            /*----------------------------------------------------------------*/
  960.  
  961.            case IDM_SAVEAS:
  962.               if ( ! CheckForTiming() ) break; /* (1) Check for untimed lines */
  963.  
  964.               if ( szCaptionFile [0] )         /* (2) Format prompt file name */
  965.                  FormatFname ( fdgSaveAs.szFullFile, szCaptionFile );
  966.               else
  967.               {
  968.                  strcpy ( fdgSaveAs.szFullFile, szTextFile );
  969.                  psz  = (PSZ) strrchr ( fdgSaveAs.szFullFile, '.' );
  970.                  pszSlash = (PSZ) strrchr ( fdgSaveAs.szFullFile, '\\' );
  971.                  if ( pszSlash < psz )  strcpy  ( (char *)psz, "._CC" );
  972.               }
  973.  
  974.               usFiledlgHelpRes = PANEL_FILEDLG_SAVEAS;/*(3)Setup Help Resource*/
  975.  
  976.               DisplaySaveasDlg(IDM_SAVEAS);                     /* (4) */
  977.               break;
  978.  
  979.  
  980.            /*------------------- Exit menu item ------------------------------*/
  981.            /*                                                                 */
  982.            /* (1) Check for any unsaved changes. If any exist, prompt the user*/
  983.            /*     to save them or cancel the Exit request.                    */
  984.            /*                                                                 */
  985.            /* (2) If step 1 went OK, then post a WM_CLOSE message to yourself.*/
  986.            /*-----------------------------------------------------------------*/
  987.  
  988.            case IDM_EXITPROG:
  989.               if ( bUnsavedChanges )
  990.                  if ( SaveChanges( MB_YESNOCANCEL ) == MBID_CANCEL ) break;
  991.  
  992.               bUnsavedChanges = FALSE;
  993.               WinPostMsg( hwnd, WM_CLOSE, 0L, 0L );
  994.               break;
  995.  
  996.  
  997.            /*------------------- Help menu items -----------------------------*/
  998.            /*                                                                 */
  999.            /* For each of the Help items, send a message to the help instance */
  1000.            /* object window to display the information the user has requested.*/
  1001.            /*-----------------------------------------------------------------*/
  1002.  
  1003.            case IDM_GENERAL_HELP:
  1004.               WinSendMsg ( hwndHelp, HM_DISPLAY_HELP,
  1005.                        MPFROMSHORT( PANEL_OVERVIEW ),
  1006.                        MPFROMSHORT( HM_RESOURCEID ) );
  1007.               break;
  1008.  
  1009.  
  1010.            case IDM_KEYS_HELP:
  1011.               WinSendMsg ( hwndHelp, HM_DISPLAY_HELP,
  1012.                        MPFROMSHORT( PANEL_KEYS_HELP ),
  1013.                        MPFROMSHORT( HM_RESOURCEID ) );
  1014.               break;
  1015.  
  1016.  
  1017.            case IDM_USING_HELP:
  1018.               WinSendMsg ( hwndHelp, HM_DISPLAY_HELP, 0, 0 );
  1019.               break;
  1020.  
  1021.  
  1022.            case IDM_HELP_INDEX:
  1023.               WinSendMsg ( hwndHelp, HM_HELP_INDEX, 0, 0 );
  1024.               break;
  1025.  
  1026.            case IDM_PRODUCT_INFO:
  1027.               /*
  1028.                * See if the product information dialog box was created.
  1029.                */
  1030.               if (!hwndProductInfo)
  1031.               {
  1032.                  /*
  1033.                   * Product Window was not created, create and display the
  1034.                   * window.
  1035.                   */
  1036.                  hwndProductInfo =
  1037.                      WinLoadSecondaryWindow(
  1038.                         HWND_DESKTOP,              /* Parent of the dialog box*/
  1039.                         hwndMainFrame,             /* Owner of the dialog box.*/
  1040.                         (PFNWP)ProductDlgProc,     /* Dialog box procedure.   */
  1041.                         (HMODULE) NULL,            /* Dialog is where,EXE file*/
  1042.                         ID_DLG_PRODUCTINFO,        /* Dialog ID.              */
  1043.                         (PVOID) NULL);             /* Dialog Creation Params  */
  1044.               }
  1045.               else
  1046.               {
  1047.                  /*
  1048.                   * Product window was created earlier, reposition the window
  1049.                   * and give the focus.
  1050.                   */
  1051.                  WinSetWindowPos(
  1052.                     hwndProductInfo,
  1053.                     HWND_TOP,
  1054.                     (SHORT) NULL,
  1055.                     (SHORT) NULL,
  1056.                     (SHORT) NULL,
  1057.                     (SHORT) NULL,
  1058.                     SWP_RESTORE | SWP_SHOW | SWP_ACTIVATE );
  1059.  
  1060.                  WinSetFocus( HWND_DESKTOP, hwndProductInfo );
  1061.               }
  1062.               break;
  1063.  
  1064.  
  1065.            /*------------- Caption lines... menu items -----------------------*/
  1066.            /*                                                                 */
  1067.            /* Since these menu items do essentially the same thing, they all  */
  1068.            /* invoke the same function ( ResizeTextWindow() ).  For details,  */
  1069.            /* see the ResizeTextWindow() function.                            */
  1070.            /*-----------------------------------------------------------------*/
  1071.  
  1072.            case IDM_2_LINES:
  1073.               ResizeTextWindow(2);
  1074.               break;
  1075.  
  1076.            case IDM_3_LINES:
  1077.               ResizeTextWindow(3);
  1078.               break;
  1079.  
  1080.            case IDM_4_LINES:
  1081.               ResizeTextWindow(4);
  1082.               break;
  1083.  
  1084.            case IDM_5_LINES:
  1085.               ResizeTextWindow(5);
  1086.               break;
  1087.  
  1088.            case IDM_6_LINES:
  1089.               ResizeTextWindow(6);
  1090.               break;
  1091.            }
  1092.         return 0;
  1093.  
  1094.      case WM_CONTROL:
  1095.         sControlID  = SHORT1FROMMP(mp1);
  1096.         usNotifyCode = (USHORT) SHORT2FROMMP(mp1);
  1097.  
  1098.         switch ( sControlID )
  1099.         {
  1100.            /*-------------------- Volume control -----------------------------*/
  1101.            /*                                                                 */
  1102.            /*  (1) Every time the volume control setting is changed, save the */
  1103.            /*      the value in a global variable:  ulVolume.                 */
  1104.            /*                                                                 */
  1105.            /*  (2) send an MCI_SET message to adjust the volume level         */
  1106.            /*-----------------------------------------------------------------*/
  1107.  
  1108.            case ID_VOLUME:
  1109.               if ( ( usNotifyCode == SLN_CHANGE ) ||
  1110.                    ( usNotifyCode == SLN_SLIDERTRACK ) )
  1111.               {
  1112.  
  1113.                  mresult = WinSendMsg( hwndVolume,
  1114.                                        SLM_QUERYSLIDERINFO,
  1115.                                        (MPARAM)MPFROM2SHORT( SMA_SLIDERARMPOSITION,
  1116.                                                              SMA_RANGEVALUE),
  1117.                                        0 );
  1118.                  ulVolume = (ULONG) SHORT1FROMMP( (MPARAM)mresult );/*(1)  */
  1119.  
  1120.                  mspSet.hwndCallback = (HWND) NULL;
  1121.                  mspSet.ulAudio    = MCI_SET_AUDIO_ALL;
  1122.                  mspSet.ulLevel    = (ULONG) ulVolume;
  1123.                  mciSendCommand ( mop.usDeviceID,      /*(2) Adj volume */
  1124.                                   MCI_SET,
  1125.                                   MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
  1126.                                   (PVOID) &mspSet,
  1127.                                   (USHORT) UP_SET );
  1128.               }
  1129.               break;
  1130.  
  1131.  
  1132.            /*----------------- Audio position slider -------------------------*/
  1133.            /*                                                                 */
  1134.            /* (1) As soon as the user drags and/or changes the audio position */
  1135.            /*     slider, we must ignore further MM_MCIPOSITIONCHANGE messages*/
  1136.            /*     coming from the audio play.  We don't want the user and     */
  1137.            /*     MMPM/2 getting into a tug-of-war over the slider position.  */
  1138.            /*     We ignore further MM_MCIPOSITIONCHANGE messages by changing */
  1139.            /*     the value of usPositionUP. Every time an MM_MCIPOSITIONCHANGE*/
  1140.            /*     message is received, its user parameter is compared with    */
  1141.            /*     usPositionUP. If they don't match, the message is ignored.  */
  1142.            /*     By changing usPositionUP, we will cause the program to ignore*/
  1143.            /*     MM_MCIPOSITIONCHANGE messages until the next play is started*/
  1144.            /*                                                                 */
  1145.            /* (2) Now we need to determine if the SLN_CHANGE message came from*/
  1146.            /*     the user or from the program.  To do this, we manipulate the*/
  1147.            /*     window focus.  If the slider window has the focus, that     */
  1148.            /*     implies that the user updated the control.                  */
  1149.            /*                                                                 */
  1150.            /* (3) Set the focus to another window so we can continue to       */
  1151.            /*     distinguish between user and program updates.               */
  1152.            /*                                                                 */
  1153.            /* (4) What we do next depends on the play status of the audio:    */
  1154.            /*                                                                 */
  1155.            /*     (4a) If the audio is stopped, reposition the captions to    */
  1156.            /*          correspond to the new audio position.                  */
  1157.            /*                                                                 */
  1158.            /*     (4b) If the audio is paused, stop the audio and then        */
  1159.            /*          reposition the captions to correspond to the new audio */
  1160.            /*          position.                                              */
  1161.            /*                                                                 */
  1162.            /*     (4c) If the audio is playing, reposition the captions, stop */
  1163.            /*          the audio and then restart it in the new position.     */
  1164.            /*-----------------------------------------------------------------*/
  1165.  
  1166.            case ID_AUDIO_SLIDER:
  1167.               if ( usNotifyCode == SLN_SLIDERTRACK )
  1168.               {
  1169.                  usPositionUP++;
  1170.                  if ( usPositionUP > 32766 )/*(1)Ignore further position change*/
  1171.                     usPositionUP = 0;      /*   messages coming from MMPM/2   */
  1172.                  break;
  1173.               }
  1174.  
  1175.               if ( ( usNotifyCode != SLN_CHANGE ) ||
  1176.                    ( WinQueryFocus ( HWND_DESKTOP ) != hwndAudioSlider ) )
  1177.                  break;                    /*(2)Ignore SLN_CHANGE messages not*/
  1178.                                            /*   originated by the user.       */
  1179.  
  1180.               WinSetFocus(HWND_DESKTOP,hwndVolume);/*(3)Change focus so we can*/
  1181.                                                    /* continue to use test(2) */
  1182.               usPositionUP++;
  1183.               if ( usPositionUP > 32766 )/*Repeat step (1) for SLN_CHANGE msgs */
  1184.                  usPositionUP = 0;
  1185.  
  1186.               sArmPosition = SHORT1FROMMP(mp2);
  1187.  
  1188.               switch ( iState )
  1189.               {                           /* (4) Depending on audio state...  */
  1190.                  case ST_OPEN:
  1191.                     PositionCaptions ( sArmPosition );
  1192.                     break;               /*(4a)Reposition captions and exit or*/
  1193.  
  1194.                  case ST_PAUSED:
  1195.                     StopPlaying( hwnd ); /* (4b) Stop, then reposition or...  */
  1196.                     PositionCaptions ( sArmPosition );
  1197.                     break;
  1198.  
  1199.                  case ST_PLAYING:
  1200.                     PositionCaptions ( sArmPosition );
  1201.                     iState = ST_SEEKING;
  1202.                     StopPlaying( hwnd ); /*(4c)Reposition captions, stop curr */
  1203.                     StartPlaying( hwnd );/*    play and restart at new pos'n  */
  1204.                     break;
  1205.               }
  1206.               break;
  1207.         }
  1208.         break;
  1209.  
  1210.      /*---------------- MM_MCIPOSITIONCHANGE message -------------------------*/
  1211.      /*                                                                       */
  1212.      /* (1) Validate the message by comparing the user parameter with the     */
  1213.      /*     variable usPositionUP. This prevents queued messages from previous*/
  1214.      /*     plays from affecting the Audio Position slider.                   */
  1215.      /*                                                                       */
  1216.      /* (2) Update the position if the audio slider, if we are still playing. */
  1217.      /*                                                                       */
  1218.      /* (3) If we are in Play mode, scan through the line data table to see if*/
  1219.      /*     we need to scroll more lines into the text window.  The index of  */
  1220.      /*     the NEXT line to be displayed can be calculated as follows        */
  1221.      /*                                                                       */
  1222.      /*            Line currently at bottom of window:    usDisplayLine +     */
  1223.      /*            Lines queued to be displayed:          usNextlineReq +     */
  1224.      /*            The line after that one:               1                   */
  1225.      /*-----------------------------------------------------------------------*/
  1226.  
  1227.      case MM_MCIPOSITIONCHANGE:
  1228.         if ((USHORT) SHORT1FROMMP(mp1) != usPositionUP) /* (1) Validate message */
  1229.            break;
  1230.  
  1231.         ulTime = (ULONG) LONGFROMMP(mp2);
  1232.  
  1233.         if ( iState == ST_PLAYING )                 /* (2) Adjust audio slider*/
  1234.         {
  1235.            sArmPosition =
  1236.                (SHORT) ( ( ulTime * ( sAudioArmRange - 1) ) / ulAudioLength );
  1237.            WinSendMsg(
  1238.               hwndAudioSlider,
  1239.               SLM_SETSLIDERINFO,
  1240.               MPFROM2SHORT( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  1241.               MPFROMSHORT( sArmPosition ));
  1242.         }
  1243.  
  1244.         if ( sLatestPlayRequest == ID_PLAY )       /* (3) Time for new line?  */
  1245.         {
  1246.            usTestLine = (USHORT) ( usDisplayLine + usNextlineReq + 1 );
  1247.            pld = (PLINEDATA) pvLinedataTable + usTestLine;
  1248.            while ( ( usTestLine < usLineCount ) && ( pld->ulTime <= ulTime ) )
  1249.            {
  1250.               usNextlineReq++;
  1251.               if ( usNextlineReq == 1 )
  1252.                  WinPostMsg ( hwndText, UM_NEXTLINE, 0, 0 );
  1253.               pld++;
  1254.               usTestLine++;
  1255.            }
  1256.         }
  1257.         return 0;
  1258.  
  1259.      case MM_MCINOTIFY:
  1260.         usNotifyCode    = (USHORT)  SHORT1FROMMP(mp1);
  1261.         usUserParm      = (USHORT)  SHORT2FROMMP(mp1);
  1262.         usCommandMessage = (USHORT) SHORT2FROMMP(mp2);
  1263.  
  1264.         switch ( usCommandMessage )
  1265.         {
  1266.            /*--------------- Play notification message -----------------------*/
  1267.            /*                                                                 */
  1268.            /*  We receive this message when a audio play has completed.       */
  1269.            /*                                                                 */
  1270.            /*  (1) Check to see if the Notification Code portion of the       */
  1271.            /*      message contained an error code.  Display the error code,  */
  1272.            /*      if present.                                                */
  1273.            /*                                                                 */
  1274.            /*  (2) If the notification code was MCI_NOTIFY_SUCCESSFUL, that   */
  1275.            /*      means that the audio has played to the end.  Invoke the    */
  1276.            /*      StopPlaying function to reset all dialog box controls.     */
  1277.            /*      Force the audio slider to its extreme right position, just */
  1278.            /*      in case the granularity of the MM_MCIPOSITIONCHANGE        */
  1279.            /*      messages left it a pixel or two short.                     */
  1280.            /*-----------------------------------------------------------------*/
  1281.  
  1282.            case MCI_PLAY:
  1283.               if ( ( usNotifyCode != MCI_NOTIFY_SUCCESSFUL ) &&
  1284.                    ( usNotifyCode != MCI_NOTIFY_SUPERSEDED ) &&
  1285.                    ( usNotifyCode != MCI_NOTIFY_ABORTED ) )
  1286.               {
  1287.                  ulError = (ULONG)usNotifyCode;/*(1)Display an audio error code*/
  1288.                  StopPlaying( hwnd );
  1289.                  AudioError ( ulError );
  1290.               }
  1291.  
  1292.               if ( usNotifyCode == MCI_NOTIFY_SUCCESSFUL )
  1293.               {                             /* (2) Audio has played to the end*/
  1294.                  StopPlaying( hwnd );
  1295.                  WinSendMsg( hwndAudioSlider, SLM_SETSLIDERINFO,
  1296.                              MPFROM2SHORT( SMA_SLIDERARMPOSITION,
  1297.                                            SMA_RANGEVALUE ),
  1298.                              MPFROMSHORT( (SHORT) ( sAudioArmRange - 1 )));
  1299.               }
  1300.         }
  1301.         return 0;
  1302.  
  1303.  
  1304.      /*-----------------------------------------------------------------------*/
  1305.      /* Every time we get an MM_MCIPASSDEVICE message, we save the state of   */
  1306.      /* the audio device in bAcquired. Whenever the Main window is activated, */
  1307.      /* we check this variable to see if we need to reacquire the audio device*/
  1308.      /*                                                                       */
  1309.      /* (1) If gaining control of the device:                                 */
  1310.      /*                                                                       */
  1311.      /*     (1a) Set bAcquired to FALSE.                                      */
  1312.      /*     (1b) If the latest request was to play start the Play button      */
  1313.      /*          animation.                                                   */
  1314.      /*     (1c) If the latest request was to set timing start the Set Timing */
  1315.      /*          button animation.                                            */
  1316.      /*                                                                       */
  1317.      /* (2) If loosing control of the device:                                 */
  1318.      /*                                                                       */
  1319.      /*     (2a) Set bAcquired to TRUE.                                       */
  1320.      /*     (2b) If the latest request was to play stop the Play button       */
  1321.      /*          animation.                                                   */
  1322.      /*     (2c) If the latest request was to set timing stop the Set Timing  */
  1323.      /*          button animation.                                            */
  1324.      /*                                                                       */
  1325.      /*-----------------------------------------------------------------------*/
  1326.  
  1327.      case MM_MCIPASSDEVICE:
  1328.         if ((USHORT)SHORT1FROMMP(mp2) == MCI_GAINING_USE) /*(1) gaining control */
  1329.         {
  1330.            bAcquired = TRUE;                         /* (1a) gained the device*/
  1331.            if ( (sLatestPlayRequest == ID_PLAY) &&   /* (1b) playing, start.. */
  1332.                 (iState == ST_PLAYING) )
  1333.            {
  1334.               WinSendDlgItemMsg ( hwndMainDlg, ID_PLAY,      /* ...animation  */
  1335.                                   GBM_ANIMATE,
  1336.                                   MPFROMSHORT((SHORT)TRUE),
  1337.                                   MPFROMSHORT((SHORT)FALSE) );
  1338.            }
  1339.            else
  1340.            if ((sLatestPlayRequest==ID_SET_TIMING)&& /*(1c)set timing, start..*/
  1341.                      (iState == ST_PLAYING) )
  1342.            {
  1343.               WinSendDlgItemMsg ( hwndMainDlg, ID_SET_TIMING, /* ...animation*/
  1344.                                   GBM_ANIMATE,
  1345.                                   MPFROMSHORT((SHORT)TRUE),
  1346.                                   MPFROMSHORT((SHORT)FALSE) );
  1347.            }
  1348.  
  1349.         }
  1350.         else                                       /* (2) loosing control     */
  1351.         {
  1352.            bAcquired = FALSE;                      /* (2a) lost the device.   */
  1353.            if ( (sLatestPlayRequest == ID_PLAY) &&   /* (1b) playing, start.. */
  1354.                 (iState == ST_PLAYING) )
  1355.            {
  1356.               WinSendDlgItemMsg( hwndMainDlg, ID_PLAY,       /* ...animation  */
  1357.                                  GBM_ANIMATE,
  1358.                                  MPFROMSHORT((SHORT)FALSE),
  1359.                                  MPFROMSHORT((SHORT)FALSE) );
  1360.            }
  1361.            else
  1362.            if ((sLatestPlayRequest==ID_SET_TIMING)&& /*(1c)set timing, start..*/
  1363.                      (iState == ST_PLAYING) )
  1364.            {
  1365.               WinSendDlgItemMsg( hwndMainDlg, ID_SET_TIMING, /* ...animation */
  1366.                                  GBM_ANIMATE,
  1367.                                  MPFROMSHORT((SHORT)FALSE),
  1368.                                  MPFROMSHORT((SHORT)FALSE) );
  1369.            }
  1370.         }
  1371.         return 0;
  1372.  
  1373.      /*-----------------------------------------------------------------------*/
  1374.      /* Before closing the Main window, check to see if the user wants to save*/
  1375.      /* any unsaved timing changes. Then close the device and return          */
  1376.      /* WinDefWindowProc to make sure a WM_QUITmessage is sent and we fall out*/
  1377.      /* of the message loop.                                                  */
  1378.      /*-----------------------------------------------------------------------*/
  1379.  
  1380.      case WM_CLOSE:
  1381.         if ( bUnsavedChanges )
  1382.         {
  1383.            SaveChanges( MB_YESNO );
  1384.         }
  1385.         if (iState != ST_CLOSED)
  1386.         {
  1387.            CloseAudioDevice( hwnd );
  1388.         }
  1389.         return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  1390.   }
  1391.   return WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 );
  1392. }
  1393.  
  1394. /******************************************************************************
  1395.  * Name         : TextWindowProc
  1396.  *
  1397.  * Description  : This function controls the text window.  It will handle
  1398.  *                received messages such as paint, timing events, etc.
  1399.  *
  1400.  * Parameters   : hwnd - Handle for the Main dialog box.
  1401.  *                msg  - Message received by the dialog box.
  1402.  *                mp1  - Parameter 1 for the just received message.
  1403.  *                mp2  - Parameter 2 for the just received message.
  1404.  *
  1405.  * Return       :
  1406.  *
  1407.  ******************************************************************************/
  1408. MRESULT EXPENTRY TextWindowProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  1409. {
  1410.    HPS          hpsPaint;               /* Handle to Text window pres space   */
  1411.    RECTL        rclPaint;               /* Area of the Text window            */
  1412.    POINTL       aptlPaint[4];           /* for bitblt                         */
  1413.  
  1414.  
  1415.    switch ( msg )
  1416.    {
  1417.       /*--------------------- Paint text window ------------------------------*/
  1418.       /*                                                                      */
  1419.       /*  The text to be painted into the text window is held in a monochrome */
  1420.       /*  bitmap whose presentation space is hpsText.                         */
  1421.       /*                                                                      */
  1422.       /*  (1) Setup blitting rectangles based on the area to be painted and   */
  1423.       /*      the scroll offset.  These rectangles are identical, except for  */
  1424.       /*      the Y-coordinates of the source rectangle.  These are Scroll    */
  1425.       /*      Offset pixels greater than the destination.  While scrolling,   */
  1426.       /*      the Scroll Offset grows continually smaller, meaning that the   */
  1427.       /*      source blitting rectangle scrolls DOWN the bitmap, while the    */
  1428.       /*      text in the window appears to scroll UP.)                       */
  1429.       /*                                                                      */
  1430.       /*  (2) Set the foreground and background colors of the Paint           */
  1431.       /*      presentation space to control the color of the background and   */
  1432.       /*      the text as it is blitted to the window.                        */
  1433.       /*----------------------------------------------------------------------*/
  1434.  
  1435.       case WM_PAINT:
  1436.          hpsPaint = WinBeginPaint ( hwnd, 0, &rclPaint );
  1437.  
  1438.          aptlPaint[0].x = rclPaint.xLeft;    /* (1) Set blit rect coordinates */
  1439.          aptlPaint[0].y = rclPaint.yBottom;
  1440.          aptlPaint[1].x = rclPaint.xRight;
  1441.          aptlPaint[1].y = rclPaint.yTop;
  1442.          aptlPaint[2].x = rclPaint.xLeft;
  1443.          aptlPaint[2].y = rclPaint.yBottom + lScrollOffset;
  1444.          aptlPaint[3].x = rclPaint.xRight;
  1445.          aptlPaint[3].y = rclPaint.yTop + lScrollOffset;
  1446.  
  1447.          GpiSetColor( hpsPaint, CLR_WHITE );    /* (2) Set background color...*/
  1448.          GpiSetBackColor( hpsPaint, CLR_DARKBLUE ); /*  ... and Text color    */
  1449.  
  1450.          GpiBitBlt(
  1451.             hpsPaint,
  1452.             hpsText,
  1453.             4,
  1454.             aptlPaint,
  1455.             ROP_SRCCOPY,
  1456.             BBO_IGNORE );
  1457.          WinEndPaint( hpsPaint );
  1458.          return (MRESULT) 1;
  1459.  
  1460.  
  1461.       /*---------------------- WM_TIMER message ------------------------------*/
  1462.       /*                                                                      */
  1463.       /*  The text window receives a WM_TIMER message whenever it is necessary*/
  1464.       /*  to scroll one more scroll increment.  When it is not scrolling, the */
  1465.       /*  timer is stopped, and no messages are received.                     */
  1466.       /*                                                                      */
  1467.       /*  (1) Decrement the Scroll Offset by the Scroll Increment.            */
  1468.       /*                                                                      */
  1469.       /*  (2) Scroll the Text window UP by the Scroll Increment.              */
  1470.       /*                                                                      */
  1471.       /*  (3) Check to see if one complete text line has been scrolled.  This */
  1472.       /*      is true if the Scroll Offset is zero.  If so:                   */
  1473.       /*                                                                      */
  1474.       /*      (3a) Stop the timer for now.                                    */
  1475.       /*                                                                      */
  1476.       /*      (3b) Decrement the number of lines queued for scrolling         */
  1477.       /*           ( usNextlineReq ).                                         */
  1478.       /*                                                                      */
  1479.       /*      (3c) If lines remain to be scrolled, send a message to yourself,*/
  1480.       /*           requesting that another line be scrolled into the window.  */
  1481.       /*           If no lines remain to be scrolled AND we are in a Start    */
  1482.       /*           Timing operation, then unhighlight the Advance Line button.*/
  1483.       /*----------------------------------------------------------------------*/
  1484.  
  1485.       case WM_TIMER:
  1486.          lScrollOffset -= CC_SCROLL_INC;         /* (1) Decrement scroll offst*/
  1487.  
  1488.          WinScrollWindow(                        /* (2) Scroll window up      */
  1489.             hwnd,
  1490.             0,
  1491.             CC_SCROLL_INC,
  1492.             NULL,
  1493.             NULL,
  1494.             0,
  1495.             NULL,
  1496.             SW_INVALIDATERGN );
  1497.  
  1498.          if ( lScrollOffset == 0 )                /* (3) Finished line?  */
  1499.          {
  1500.             WinStopTimer ( hab, hwnd, CC_TIMER_ID );   /* (3a) Stop timer     */
  1501.             if ( usNextlineReq )                 /* (3b) Decrement queued lns */
  1502.                usNextlineReq--;
  1503.             if ( usNextlineReq )                 /* (3c) See if more lines    */
  1504.                WinSendMsg( hwnd, UM_NEXTLINE, 0, 0 ); /* need to be scrolled  */
  1505.             else
  1506.                if ( sLatestPlayRequest == ID_SET_TIMING )
  1507.                   WinSendDlgItemMsg (            /* Unhighlight Advance Line  */
  1508.                      hwndMainDlg,
  1509.                      ID_NEXTLINE,
  1510.                      GBM_SETBITMAPINDEX,
  1511.                      MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1512.          }
  1513.          break;
  1514.  
  1515.  
  1516.       /*------------------------ UM_NEXTLINE ---------------------------------*/
  1517.       /*                                                                      */
  1518.       /*  This message requests the Text window to scroll the next line of    */
  1519.       /*  text into the window.                                               */
  1520.       /*                                                                      */
  1521.       /*  (1) Increment the index of the bottom-most line which is to be      */
  1522.       /*      displayed in the text window. ( usDisplayLine )                 */
  1523.       /*                                                                      */
  1524.       /*  (2) Redraw the backup text bitmap with the new line of text at the  */
  1525.       /*      bottom.                                                         */
  1526.       /*                                                                      */
  1527.       /*  (3) Initialize the scroll offset to the Line Spacing.               */
  1528.       /*                                                                      */
  1529.       /*  (4) Start the timer.  As each WM_TIMER message is received, the text*/
  1530.       /*      window will scroll up by one Scroll Increment                   */
  1531.       /*----------------------------------------------------------------------*/
  1532.  
  1533.       case UM_NEXTLINE:
  1534.          usDisplayLine++;                       /* (1) Inc Display Line Index */
  1535.          DisplayTextLine();                     /* (2) Redraw backup bitmap   */
  1536.          lScrollOffset = lLineSpacing;          /* (3) Initialize scroll offst*/
  1537.          WinStartTimer( hab, hwnd, CC_TIMER_ID, 100 );/* (4) Start the timer. */
  1538.          return 0;
  1539.  
  1540.    }
  1541.    return WinDefWindowProc ( hwnd, msg, mp1, mp2 );
  1542. }
  1543.  
  1544.  
  1545. /******************************************************************************
  1546.  * Name         : FileFilterProc
  1547.  *
  1548.  * Description  : This function filters the messages to the File dialog
  1549.  *                procedure.  It intercepts WM_HELP messages and invokes the
  1550.  *                help screen when it encounters.
  1551.  *
  1552.  * Parameters   : hwnd - Handle for the Main dialog box.
  1553.  *                msg  - Message received by the dialog box.
  1554.  *                mp1  - Parameter 1 for the just received message.
  1555.  *                mp2  - Parameter 2 for the just received message.
  1556.  *
  1557.  * Return       :
  1558.  *
  1559.  ******************************************************************************/
  1560. MRESULT EXPENTRY FileFilterProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  1561. {
  1562.    CHAR szError[ERROR_LENGTH];
  1563.  
  1564.  
  1565.    if ( msg == WM_HELP )
  1566.    {
  1567.       if ( WinSendMsg ( hwndHelp, HM_DISPLAY_HELP,
  1568.                         MPFROMSHORT ( (SHORT) usFiledlgHelpRes ),
  1569.                         MPFROMSHORT ( HM_RESOURCEID ) ) )
  1570.       {
  1571.          WinLoadString ( hab, (HMODULE)NULL, STRID_HELP_CREATION_FAILED,
  1572.                          ERROR_LENGTH, szError );
  1573.  
  1574.          WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szErrorMsgTitle,
  1575.                                           0, MB_OK | MB_ERROR | MB_MOVEABLE);
  1576.       }
  1577.       return (MRESULT) FALSE;
  1578.    }
  1579.    return WinDefFileDlgProc( hwnd, msg, mp1, mp2 ) ;
  1580. }
  1581.  
  1582.  
  1583. /******************************************************************************
  1584.  * Name         : FormatFname
  1585.  *
  1586.  * Description  : This function format the file name for the dialog boxes.
  1587.  *                This function accepts a name of the from x:\path\file.ext
  1588.  *                and returns a name of the form x:\path\*.ext
  1589.  *
  1590.  * Parameters   : szInputName  - accepted file name
  1591.  *                szOutputName - returned file name
  1592.  *
  1593.  * Return       : none.
  1594.  *
  1595.  ******************************************************************************/
  1596. VOID FormatFname ( CHAR szOutputName[], CHAR szInputName[] )
  1597. {
  1598.    CHAR   szWorkName[CCHMAXPATH];
  1599.    PCHAR  pcharStart, pcharEnd;
  1600.  
  1601.  
  1602.    strcpy ( szWorkName, szInputName );
  1603.  
  1604.    pcharEnd = strrchr ( szWorkName, (int) '\\' );
  1605.    if ( pcharEnd )
  1606.    {                                      /*----------------------------------*/
  1607.       *pcharEnd = 0;                      /* A directory name (and possibly a */
  1608.       strcpy ( szOutputName, szWorkName );/* drive letter) was present.  Copy */
  1609.       strcat ( szOutputName, "\\" );      /* these to the output name.        */
  1610.       pcharStart = pcharEnd + 1;          /*----------------------------------*/
  1611.    }
  1612.    else
  1613.    {
  1614.       pcharEnd = strrchr ( szWorkName, (int) ':' );
  1615.       if ( pcharEnd )
  1616.       {                                     /*--------------------------------*/
  1617.          *pcharEnd = 0;                     /*No directory found, but there IS*/
  1618.          strcpy ( szOutputName, szWorkName);/*a drive letter. Copy the drive  */
  1619.          strcat ( szOutputName, ":" );      /*letter to the output name.      */
  1620.          pcharStart = pcharEnd + 1;         /*--------------------------------*/
  1621.       }
  1622.       else
  1623.       {                                      /*-------------------------------*/
  1624.          szOutputName[0] = 0;                /* No directory or drive letter  */
  1625.          pcharStart = szWorkName;            /* was present.                  */
  1626.       }                                      /*-------------------------------*/
  1627.    }
  1628.  
  1629.    strcat ( szOutputName, "*" );        /* Now tack on the new file name: "*" */
  1630.  
  1631.    pcharEnd = strrchr ( pcharStart, '.' );   /*-------------------------------*/
  1632.    if ( pcharEnd )                           /*Tack on the original extension,*/
  1633.       strcat ( szOutputName, pcharEnd );     /*if present.                    */
  1634. }                                            /*-------------------------------*/
  1635.  
  1636. /******************************************************************************
  1637.  * Name         : LoadAudioFile
  1638.  *
  1639.  * Description  : This function will open the audio device with a selected
  1640.  *                audio file, if the audio device is not opened.  If the
  1641.  *                audio device is open, the selected audio file will be loaded
  1642.  *                onto it.  Also querys the length of the audio file, calibrates
  1643.  *                the scale on the audio slider and position the captions at
  1644.  *                the beginning of the caption file.
  1645.  *
  1646.  * Concepts     : - Open a device using the MCi interface.
  1647.  *                - Loading a file into an already open device.
  1648.  *
  1649.  * MMPM/2 API's : mciSendCommand  MCI_OPEN
  1650.  *                                MCI_LOAD
  1651.  *                                MCI_STATUS
  1652.  *
  1653.  * Parameters   : hwnd       - main window handle
  1654.  *                szFilename - selected audio file
  1655.  *
  1656.  * Return       : ulError    - if an error occured.
  1657.  *
  1658.  ******************************************************************************/
  1659. ULONG LoadAudioFile ( HWND hwnd, CHAR szFilename[] )
  1660. {
  1661.    ULONG   ulError;
  1662.    CHAR    szAudioPosSeconds[TITLE_LENGTH];     /* Title for Audio Slider     */
  1663.    CHAR    szAudioPosMinutes[TITLE_LENGTH];     /* Title for Audio Slider     */
  1664.    ULONG   ulAudioLengthMsec;                   /* For audio length in Msec   */
  1665.    ULONG   ulAudioLengthSec;                    /* For audio length in Sec    */
  1666.    ULONG   ulAudioLengthMin;                    /* For audio length in Minutes*/
  1667.    CHAR    szAudioLength[10];                   /* For audio length           */
  1668.    CHAR    szAudioMin[10];                      /* Audio length in ASCII      */
  1669.    CHAR    szAudioSec[10];                      /* Audio length in ASCII      */
  1670.    MRESULT mresult;                             /* for slider result          */
  1671.    PCHAR   pcAudioFile;                         /* audio file name            */
  1672.    CHAR    szBuffer[CCHMAXPATH];                /* buffer to hold file name   */
  1673.    static  MCI_LOAD_PARMS     mlp;              /* Load params                */
  1674.  
  1675.  
  1676.    /* If the audio device is closed, open it.  */
  1677.    if ( iState == ST_CLOSED )
  1678.    {
  1679.       mop.hwndCallback     = hwndMainDlg;         /*--------------------------*/
  1680.       mop.usDeviceID       = (USHORT)  NULL;      /*     Attempt to open      */
  1681.       mop.pszDeviceType    = (PSZ)NULL;           /*    the digital audio     */
  1682.       mop.pszElementName   = (PSZ)szFilename;     /*         device.          */
  1683.       ulError = mciSendCommand ( (USHORT) 0,      /*--------------------------*/
  1684.                                  MCI_OPEN,
  1685.                                  MCI_WAIT | MCI_OPEN_SHAREABLE |
  1686.                                  MCI_OPEN_ELEMENT | MCI_READONLY,
  1687.                                  (PVOID) &mop,
  1688.                                  (USHORT) UP_OPEN );
  1689.  
  1690.       if ( ulError )
  1691.       {
  1692.          CloseAudioDevice( hwnd );
  1693.          return ulError;
  1694.       }
  1695.    }
  1696.    else
  1697.    {
  1698.       mlp.hwndCallback     = (HWND) NULL;         /*--------------------------*/
  1699.       mlp.pszElementName   = (PSZ)szFilename;     /*     Attempt to load the  */
  1700.       ulError =                                   /*     requested audio file */
  1701.         mciSendCommand( (USHORT) mop.usDeviceID,  /*--------------------------*/
  1702.                         MCI_LOAD,
  1703.                         MCI_WAIT | MCI_READONLY,
  1704.                         (PVOID) &mlp,
  1705.                         (USHORT) UP_LOAD );
  1706.  
  1707.       if ( ulError )
  1708.       {
  1709.          CloseAudioDevice( hwnd );
  1710.          return ulError;
  1711.       }
  1712.    }
  1713. /*---------------  The load attempt was successful  --------------------------*/
  1714. /*                                                                            */
  1715. /* (1) Set the program state switches and the dialog-box status window to     */
  1716. /*     reflect the new state.                                                 */
  1717. /*                                                                            */
  1718. /* (2) Ask MMPM/2 how long the audio file is ( in MM units ) and use this     */
  1719. /*     number to calibrate the scale on the audio slider.  The scale is       */
  1720. /*     calibrated in seconds if the length is less than 60 seconds, and in    */
  1721. /*     minutes and seconds if the length is 60 seconds or greater.  Set the   */
  1722. /*     audio slider bar all the way to the left.                              */
  1723. /*                                                                            */
  1724. /* (3) Position the captions at the beginning of the caption file.            */
  1725. /*                                                                            */
  1726. /* (4) Enable the Rewind button and possibly the Start Timing and Play buttons*/
  1727. /*     in the dialog box.                                                     */
  1728. /*                                                                            */
  1729. /*----------------------------------------------------------------------------*/
  1730.  
  1731.    iState       = ST_OPEN;                        /* (1) Set state switches.. */
  1732.  
  1733.    bAudioLoaded = TRUE;
  1734.  
  1735.    msp.hwndCallback = (HWND) NULL;                 /*-------------------------*/
  1736.    msp.ulItem     = MCI_STATUS_LENGTH;             /* (2)  Ascertain the      */
  1737.    mciSendCommand ( (USHORT) mop.usDeviceID,       /*    play length of the   */
  1738.                     MCI_STATUS,                    /*       audio file.       */
  1739.                     MCI_WAIT | MCI_STATUS_ITEM,    /*-------------------------*/
  1740.                     (PVOID) &msp,
  1741.                     (USHORT) UP_STATUS );
  1742.  
  1743.    ulAudioLength     = msp.ulReturn;                 /*-----------------------*/
  1744.                                                      /* (2) Initialize the    */
  1745.    ulAudioLengthMsec = MSECFROMMM ( ulAudioLength ); /*     audio position    */
  1746.    ulAudioLengthSec  = ulAudioLengthMsec / 1000;     /*     slider control    */
  1747.                                                      /*-----------------------*/
  1748.    if ( ulAudioLengthSec >= 60 )
  1749.    {
  1750.       ulAudioLengthSec %= 60;
  1751.       ulAudioLengthMin  = ( ulAudioLengthMsec / 60000 );
  1752.       sprintf(szAudioLength, "%01lu:%02lu", ulAudioLengthMin, ulAudioLengthSec);
  1753.       WinLoadString( hab, 0, STRID_AUDIO_POS_MINUTES,
  1754.                      TITLE_LENGTH, szAudioPosMinutes );
  1755.       WinSetWindowText( WinWindowFromID( hwnd, ID_AUDIO_POSITION ),
  1756.                         szAudioPosMinutes );
  1757.    }
  1758.    else
  1759.    {
  1760.       sprintf ( szAudioLength, "%lu", ulAudioLengthSec );
  1761.       WinLoadString( hab, 0, STRID_AUDIO_POS_SECONDS,TITLE_LENGTH,
  1762.                          szAudioPosSeconds );
  1763.       WinSetWindowText ( WinWindowFromID( hwnd, ID_AUDIO_POSITION ),
  1764.                          szAudioPosSeconds );
  1765.    }
  1766.  
  1767.    WinEnableWindow   ( hwndAudioSlider, TRUE );
  1768.  
  1769.    WinSendMsg ( hwndAudioSlider, SLM_SETSCALETEXT,
  1770.                 MPFROMSHORT ( (SHORT) ( AUDIO_SLIDER_TICKS - 1 ) ),
  1771.                 MPFROMP ( szAudioLength ) );
  1772.    WinSendMsg ( hwndAudioSlider, SLM_SETSCALETEXT, 0,
  1773.                 MPFROMP ( "0" ) );
  1774.    WinSendMsg ( hwndAudioSlider, SLM_SETSLIDERINFO,
  1775.                 MPFROM2SHORT ( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  1776.                 MPFROMSHORT  ( 0 ) );
  1777.    mresult = WinSendMsg( hwndAudioSlider, SLM_QUERYSLIDERINFO,
  1778.                          MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), 0);
  1779.    sAudioArmRange = SHORT2FROMMP ( (MPARAM) mresult );
  1780.  
  1781.    PositionCaptions ( 0 );                  /* (3) Position captions at start */
  1782.  
  1783.                                             /* (4) Enable dlg box pushbuttons */
  1784.    WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_REWIND ), TRUE );
  1785.  
  1786.    if ( bTextLoaded )
  1787.       WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_SET_TIMING ), TRUE );
  1788.    if ( bCaptionsLoaded )
  1789.       WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_PLAY ), TRUE );
  1790.  
  1791.    pcAudioFile = strrchr( szFilename, '\\' );
  1792.    pcAudioFile++;
  1793.    strcpy(szBuffer, szAudioFileName);
  1794.    strcat(szBuffer, pcAudioFile);
  1795.    WinSetWindowText( WinWindowFromID( hwnd, ID_AUDIOTXT), szBuffer );
  1796.  
  1797.    return ulError;
  1798. }
  1799.  
  1800.  
  1801. /******************************************************************************
  1802.  * Name         : StartPlaying
  1803.  *
  1804.  * Description  : This function will begin the playing of an audio file from
  1805.  *                the location indicated by the audio slider and it will
  1806.  *                continue until the end of file. It is invoked when the user
  1807.  *                selects the Start timing or Play pushbutton on the Captions
  1808.  *                main window.
  1809.  *
  1810.  * Concepts     : Playing an audio file using MCI interface.
  1811.  *
  1812.  * MMPM/2 API's : mciSendCommand  MCI_PLAY
  1813.  *
  1814.  * Parameters   : hwnd       - main window handle
  1815.  *
  1816.  * Return       : ulError    - if an error occured.
  1817.  *
  1818.  ******************************************************************************/
  1819. ULONG StartPlaying ( HWND hwnd )
  1820. {
  1821.    static  MCI_PLAY_PARMS   mpp;       /* parms for MCI_PLAY                  */
  1822.    static  MCI_POSITION_PARMS mppPos;  /* parms for MCI_SET_POSITION_ADVISE   */
  1823.    ULONG   ulError;                    /* Return code                         */
  1824.    MRESULT mresultSlider; /*--------------------------------------------------*/
  1825.    SHORT   sArmPosition;  /*Read the slider position to determine the start of*/
  1826.    ULONG   ulStartPos;    /*the audio play. If the slider is at the extreme   */
  1827.                           /*right of its range, start over at the beginning.  */
  1828.                           /*--------------------------------------------------*/
  1829.  
  1830.    mresultSlider =
  1831.           WinSendMsg( hwndAudioSlider, SLM_QUERYSLIDERINFO,
  1832.                       MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_RANGEVALUE), 0 );
  1833.    sArmPosition = SHORT1FROMMP ( (MPARAM) mresultSlider );
  1834.  
  1835.    if ( sArmPosition >=  ( sAudioArmRange - 1 ) )
  1836.    {
  1837.       ulStartPos = 0;
  1838.       WinSendMsg( hwndAudioSlider, SLM_SETSLIDERINFO,
  1839.                   MPFROM2SHORT ( SMA_SLIDERARMPOSITION, SMA_RANGEVALUE ),
  1840.                   MPFROMSHORT  ( 0 ) );
  1841.       PositionCaptions ( 0 );
  1842.    }
  1843.    else
  1844.       ulStartPos = (ULONG)((sArmPosition * ulAudioLength)/(sAudioArmRange - 1));
  1845.  
  1846.  
  1847.    mpp.hwndCallback = hwndMainDlg;
  1848.    mpp.ulFrom = ulStartPos;
  1849.    ulError =  mciSendCommand ( mop.usDeviceID,        /*--------------------*/
  1850.                                MCI_PLAY,              /*          Start     */
  1851.                                MCI_NOTIFY | MCI_FROM, /*         playback.  */
  1852.                                (PVOID) &mpp,          /*--------------------*/
  1853.                                (USHORT) UP_PLAY );
  1854.  
  1855.    if ( ulError )
  1856.    {
  1857.       StopPlaying( hwnd );
  1858.       return ulError;
  1859.    }
  1860.  
  1861.  
  1862.  /*------------------------------------------------------------------------*/
  1863.  /*                                                                        */
  1864.  /*         If there were no errors starting the play:                     */
  1865.  /*                                                                        */
  1866.  /*        (1) Request position advise messages.                           */
  1867.  /*        (2) Enable PAUSE and STOP controls.                             */
  1868.  /*        (3) Begin animating the button that started the play            */
  1869.  /*            ( either PLAY or SET TIMING )                               */
  1870.  /*                                                                        */
  1871.  /*------------------------------------------------------------------------*/
  1872.  
  1873.    iState = ST_PLAYING;                    /* Set state to reflect play mode */
  1874.  
  1875.    mppPos.hwndCallback = hwndMainDlg;      /*-----------------------------*/
  1876.    mppPos.ulUnits    = 1500;               /* (1) Request position advise */
  1877.    mppPos.usUserParm = usPositionUP;       /*             messages.       */
  1878.    mppPos.Reserved0  = 0;                  /*-----------------------------*/
  1879.    mciSendCommand    ( mop.usDeviceID,
  1880.                        MCI_SET_POSITION_ADVISE,
  1881.                        MCI_NOTIFY | MCI_SET_POSITION_ADVISE_ON,
  1882.                        (PVOID) &mppPos,
  1883.                        UP_POSITION );
  1884.  
  1885.    WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_PAUSE  ), TRUE  );/*(2) */
  1886.    WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_STOP   ), TRUE  );
  1887.  
  1888.    switch ( sLatestPlayRequest )        /* (3) Start animating the button that*/
  1889.       {                                 /*     initiated the play operation.  */
  1890.       case ID_SET_TIMING:
  1891.          WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_PLAY ), FALSE );
  1892.          WinSendDlgItemMsg(hwndMainDlg, ID_SET_TIMING, GBM_ANIMATE,
  1893.                            MPFROMSHORT((SHORT)TRUE), MPFROMSHORT((SHORT)FALSE));
  1894.          WinEnableWindow( WinWindowFromID ( hwndMainDlg, ID_NEXTLINE ), TRUE );
  1895.          WinSendDlgItemMsg(hwndMainDlg, ID_NEXTLINE, GBM_SETBITMAPINDEX,
  1896.                            MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1897.          break;
  1898.  
  1899.       case ID_PLAY:
  1900.          WinEnableWindow( WinWindowFromID( hwndMainDlg, ID_SET_TIMING ), FALSE);
  1901.          WinSendDlgItemMsg(hwndMainDlg, ID_PLAY, GBM_ANIMATE,
  1902.                            MPFROMSHORT((SHORT)TRUE), MPFROMSHORT((SHORT)FALSE));
  1903.    }
  1904.    return ulError;
  1905. }
  1906.  
  1907. /******************************************************************************
  1908.  * Name         : StopPlaying
  1909.  *
  1910.  * Description  : This function will stop the device that is playing.
  1911.  *
  1912.  * Concepts     : Stopping a device using MCI interface.
  1913.  *
  1914.  * MMPM/2 API's : mciSendCommand  MCI_STOP
  1915.  *
  1916.  * Parameters   : hwnd       - main window handle
  1917.  *
  1918.  * Return       : none.
  1919.  *
  1920.  ******************************************************************************/
  1921. VOID StopPlaying ( HWND hwnd )
  1922. {
  1923.    /***************************************************************************/
  1924.    /*                                                                         */
  1925.    /* (1) Send a message to MMPM/2 requesting the current play to stop.       */
  1926.    /*                                                                         */
  1927.    /* (2) Update the internal status to indicate that the play has stopped.   */
  1928.    /*     Show the new state in the status line in the main dialog box.       */
  1929.    /*                                                                         */
  1930.    /* (3) Disable the Pause, Stop and Advance Line controls                   */
  1931.    /*                                                                         */
  1932.    /* (4) Stop animating the button which requested the audio play ( either   */
  1933.    /*     Play or Start Timing ).                                             */
  1934.    /*                                                                         */
  1935.    /* (5) Enable the File, Help and Options submenus.                         */
  1936.    /***************************************************************************/
  1937.  
  1938.    usNextlineReq  = 0;
  1939.    mgp.hwndCallback = 0;                /*-------------------------------------*/
  1940.    mciSendCommand ( mop.usDeviceID,     /*                                     */
  1941.                     MCI_STOP,           /*(1) Issue an MCI_STOP command for the*/
  1942.                     MCI_WAIT,           /*    audio file.                      */
  1943.                     (PVOID) &mgp,       /*                                     */
  1944.                     (USHORT) UP_STOP ); /*-------------------------------------*/
  1945.  
  1946.    iState = ST_OPEN;                   /*(2) Update internal & external status*/
  1947.  
  1948.    WinSendDlgItemMsg( hwndMainDlg, ID_PAUSE, GBM_SETBITMAPINDEX,
  1949.                                  MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1950.    WinSendDlgItemMsg( hwndMainDlg, ID_NEXTLINE, GBM_SETBITMAPINDEX,
  1951.                                  MPFROMSHORT(GB_CURRENTSTATE), MPFROMSHORT(0) );
  1952.  
  1953.    WinEnableWindow ( WinWindowFromID( hwndMainDlg, ID_PAUSE   ), FALSE );
  1954.    WinEnableWindow ( WinWindowFromID( hwndMainDlg, ID_STOP    ), FALSE );/*(3)*/
  1955.    WinEnableWindow ( WinWindowFromID( hwndMainDlg, ID_NEXTLINE), FALSE );
  1956.  
  1957.    switch ( sLatestPlayRequest )      /* (4) Stop animating the graphic button*/
  1958.    {                                  /*     which started the PLAY operation.*/
  1959.       case ID_SET_TIMING:
  1960.          WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_PLAY ), TRUE );
  1961.          WinSendDlgItemMsg ( hwndMainDlg, ID_SET_TIMING, GBM_ANIMATE,
  1962.                              MPFROMSHORT((SHORT)FALSE),
  1963.                              MPFROMSHORT((SHORT)FALSE) );
  1964.          break;
  1965.  
  1966.       case ID_PLAY:
  1967.          WinEnableWindow( WinWindowFromID( hwndMainDlg, ID_SET_TIMING ), TRUE);
  1968.          WinSendDlgItemMsg ( hwndMainDlg, ID_PLAY, GBM_ANIMATE,
  1969.                              MPFROMSHORT((SHORT)FALSE),
  1970.                              MPFROMSHORT((SHORT)FALSE) );
  1971.    }
  1972.    bAcceptPlayRequests = TRUE;
  1973. }
  1974.  
  1975. /******************************************************************************
  1976.  * Name         : CloseAudioDevice
  1977.  *
  1978.  * Description  : This function will close the audio device.
  1979.  *
  1980.  * Concepts     : Closing a device using MCI interface.
  1981.  *
  1982.  * MMPM/2 API's : mciSendCommand  MCI_CLOSE
  1983.  *
  1984.  * Parameters   : hwnd       - main window handle
  1985.  *
  1986.  * Return       : none.
  1987.  *
  1988.  ******************************************************************************/
  1989. VOID CloseAudioDevice ( HWND hwnd )
  1990. {
  1991.    mgp.hwndCallback = (HWND) NULL;       /*-----------------------------------*/
  1992.    mciSendCommand ( mop.usDeviceID,      /*                                   */
  1993.                     MCI_CLOSE,           /*                                   */
  1994.                     MCI_WAIT,            /* Close the digital audio device.   */
  1995.                     (PVOID) &mgp,        /*                                   */
  1996.                     (USHORT) UP_CLOSE ); /*                                   */
  1997.                                          /*-----------------------------------*/
  1998.    iState            = ST_CLOSED;
  1999. }
  2000.  
  2001.  
  2002. /******************************************************************************
  2003.  * Name         : ShareAudioDevice
  2004.  *
  2005.  * Description  : This function will control audio device sharing.
  2006.  *                Every time the activation status of the main window changes,
  2007.  *                this function will be invoked to see if we needed to regain
  2008.  *                the control of the audio device.
  2009.  *
  2010.  * Concepts     : Sharing a audio device using MCI interface.
  2011.  *
  2012.  * MMPM/2 API's : mciSendCommand  MCI_ACQUIREDEVICE
  2013.  *
  2014.  * Parameters   : none.
  2015.  *
  2016.  * Return       : none.
  2017.  *
  2018.  ******************************************************************************/
  2019. VOID ShareAudioDevice ( void )
  2020. {
  2021.  
  2022.    if ( bMainActive && ( iState != ST_CLOSED ) && ! bAcquired )
  2023.    {
  2024.       mgp.hwndCallback = hwndMainDlg;     /*----------------------------------*/
  2025.       mciSendCommand( mop.usDeviceID,     /*Request the device if:            */
  2026.                       MCI_ACQUIREDEVICE,  /* (a) Either window active   AND...*/
  2027.                       (ULONG)MCI_NOTIFY,  /* (b) We have the device open AND..*/
  2028.                       (PVOID) &mgp,       /* (c) We don't own the device    . */
  2029.                       (USHORT)NULL);      /*----------------------------------*/
  2030.    }
  2031. }
  2032.  
  2033.  
  2034. /******************************************************************************
  2035.  * Name         : AudioError
  2036.  *
  2037.  * Description  : This function will display the MCI error message based upon
  2038.  *                the ulError return code.  The MCI function mciGetErrorString
  2039.  *                is used to convert the error code into a text string. The
  2040.  *                resulting string will displayed to the user.
  2041.  *
  2042.  * Concepts     : Using mciGetErrorString to convert an error code into a
  2043.  *                textual message.
  2044.  *
  2045.  * MMPM/2 API's : mciGetErrorString
  2046.  *
  2047.  * Parameters   : ulError  - MCI error code
  2048.  *
  2049.  * Return       : none.
  2050.  *
  2051.  ******************************************************************************/
  2052. VOID AudioError ( ULONG ulError )
  2053. {
  2054.    CHAR  szErrorMessage [ERROR_LENGTH];
  2055.  
  2056.  
  2057.    mciGetErrorString ( ulError, (PSZ)szErrorMessage, ERROR_LENGTH );
  2058.  
  2059.    WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szErrorMessage, szErrorMsgTitle,
  2060.                                            0, MB_OK | MB_ERROR | MB_MOVEABLE );
  2061. }
  2062.  
  2063.  
  2064. /******************************************************************************
  2065.  * Name         : LoadTextFile
  2066.  *
  2067.  * Description  : This function will load the selected text or caption file
  2068.  *                for processing.
  2069.  *
  2070.  * Parameters   : szFilename - selected text file
  2071.  *
  2072.  * Return       : apiret     - if an error occured.
  2073.  *
  2074.  ******************************************************************************/
  2075. APIRET LoadTextFile ( CHAR szFilename[] )
  2076. {
  2077.    APIRET    apiret;         /* DOS return code                               */
  2078.    HFILE     hfile;          /* Text file handle                              */
  2079.    ULONG     ulAction;       /* Parameter returned by various DOS API func.   */
  2080.    ULONG     ulFileSize;     /* Expected file size                            */
  2081.    PLINEDATA pld;            /* Used in building the Line Data Table          */
  2082.    PSZ       psz;
  2083.    PLINEDATA pldIn, pldOut;
  2084.    PVOID     pvTextBackup;   /* Temporary holding area for pvText             */
  2085.    MRESULT   mresult;        /* Data returned for queries of slider arm info. */
  2086.    SHORT     sArmPosition;   /* Audio slider arm position                     */
  2087.  
  2088.  
  2089. /*----------------------- Open the text file ---------------------------------*/
  2090.  
  2091.    apiret = DosOpen ( (PSZ) szFilename, &hfile, &ulAction, 0,
  2092.                       FILE_NORMAL | FILE_READONLY, FILE_OPEN,
  2093.                       OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE, NULL );
  2094.  
  2095.    if ( apiret ) return apiret;
  2096.  
  2097.  
  2098. /*------------ Read the entire file into a memory area -----------------------*/
  2099.  
  2100.    pvTextBackup = pvText;                   /* Save the currently-loaded text */
  2101.                                             /* data in case the open fails.   */
  2102.  
  2103.    DosSetFilePtr( hfile, 0, FILE_END, &ulFileSize );/*Determine file size and */
  2104.    apiret = DosAllocMem(&pvText, ulFileSize, fALLOC);/* allocate memory for it*/
  2105.  
  2106.    if ( apiret)                 /*----------- Open failed --------------------*/
  2107.    {                            /*                                            */
  2108.       DosClose ( hfile );       /* Return the error code to the user and      */
  2109.       pvText = pvTextBackup;    /* restore the previous text data pointer.    */
  2110.       return apiret;            /*--------------------------------------------*/
  2111.    }
  2112.  
  2113.    DosSetFilePtr ( hfile, 0, FILE_BEGIN, &ulAction );  /* Read the file image */
  2114.    apiret = DosRead( hfile, pvText, ulFileSize, &ulAction );/* into the buffer*/
  2115.    DosClose ( hfile );
  2116.    if ( ! apiret && ( ulFileSize != ulAction ) ) apiret = ERROR_UNEXPECTED_EOF;
  2117.  
  2118.    if ( apiret )                /*----------- Read failed --------------------*/
  2119.    {                            /*                                            */
  2120.       DosFreeMem ( pvText );    /* Return the error code to the user and      */
  2121.       pvText = pvTextBackup;    /* restore the previous text data pointer.    */
  2122.       return apiret;            /*--------------------------------------------*/
  2123.    }
  2124.  
  2125.  
  2126. /*----------------------------------------------------------------------------*/
  2127. /*                                                                            */
  2128. /* At this point, the existing text or caption file must be unloaded.  Set the*/
  2129. /* dialog box controls to reflect this state, just in case something goes     */
  2130. /* wrong while setting up the new text or caption file.                       */
  2131. /*                                                                            */
  2132. /*----------------------------------------------------------------------------*/
  2133.  
  2134.    DosFreeMem ( pvTextBackup );          /* Free previously-loaded text data. */
  2135.  
  2136.    bTextLoaded     = FALSE;              /* Set internal switches             */
  2137.    bCaptionsLoaded = FALSE;
  2138.    bUnsavedChanges = FALSE;
  2139.    szTextFile[0] = 0;
  2140.    szCaptionFile[0] = 0;
  2141.  
  2142.    GpiErase ( hpsText );                 /* Blankout text window              */
  2143.    WinInvalidateRect ( hwndText, NULL, FALSE );
  2144.  
  2145.    WinSendMsg ( hwndMenu, MM_SETITEMATTR,/* Disable Save and Save as... menus */
  2146.                 MPFROM2SHORT ( IDM_SAVE, TRUE ),
  2147.                 MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED ) );
  2148.    WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2149.                 MPFROM2SHORT ( IDM_SAVEAS, TRUE ),
  2150.                 MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED ) );
  2151.  
  2152.    WinEnableWindow  ( WinWindowFromID ( hwndMainDlg, ID_SET_TIMING ), FALSE );
  2153.    WinEnableWindow  ( WinWindowFromID ( hwndMainDlg, ID_PLAY       ), FALSE );
  2154.  
  2155.  
  2156. /*----------------------------------------------------------------------------*/
  2157. /*                                                                            */
  2158. /*  Convert the file image to a series of NULL-terminated strings by changing */
  2159. /*  all carriage-returns to NULLs.  Build the Line Data Table with an entry   */
  2160. /*  pointing to each string.  When done, usLineCount will contain a count of  */
  2161. /*  the entries used in the Line Data Table.                                  */
  2162. /*                                                                            */
  2163. /*----------------------------------------------------------------------------*/
  2164.  
  2165.    pld = (PLINEDATA) pvLinedataTable;
  2166.    psz = (PSZ) pvText;
  2167.  
  2168.    for ( usLineCount = 1; usLineCount < MAX_TEXT_LINES; usLineCount++ )
  2169.    {
  2170.       pld->szText = psz;
  2171.       pld->ulTime = LINE_NOT_TIMED;
  2172.       psz = (PSZ) memchr ( pvText, CHAR_RETURN, (size_t) ulFileSize );
  2173.       if ( psz == NULL ) break;
  2174.       *psz = CHAR_NULL;
  2175.       psz += 2;
  2176.       if ( *psz == CHAR_EOF ) break;
  2177.       pld++;
  2178.    }
  2179.    if ( usLineCount == MAX_TEXT_LINES ) return (APIRET) ERROR_TOO_MANY_LINES;
  2180.  
  2181.    bTextLoaded = TRUE;
  2182.  
  2183.  
  2184. /*------- Put the length of each string in the Line Data Table ---------------*/
  2185.  
  2186.    pld = (PLINEDATA) pvLinedataTable;
  2187.    for ( usDisplayLine = 0; usDisplayLine < usLineCount; usDisplayLine++ )
  2188.    {
  2189.       pld->lTextLen = (LONG) strlen ( pld->szText );
  2190.       pld++;
  2191.    }
  2192.  
  2193.  
  2194. /*----------------------------------------------------------------------------*/
  2195. /*                                                                            */
  2196. /* If the user has loaded a text file that is already in Caption format,      */
  2197. /* build the Line Data Table from the information already present in the file.*/
  2198. /* If the file is plain text, mark the first line for immediate display.      */
  2199. /*                                                                            */
  2200. /*----------------------------------------------------------------------------*/
  2201.  
  2202.    pldOut = (PLINEDATA) pvLinedataTable;
  2203.  
  2204.    if ( ! strcmp ( (PCHAR) pldOut->szText, szCC_FILE ) )
  2205.    {
  2206.       bCaptionsLoaded = TRUE;
  2207.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVE,   TRUE ),
  2208.                                              MPFROM2SHORT ( MIA_DISABLED, 0 ) );
  2209.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVEAS, TRUE ),
  2210.                                              MPFROM2SHORT ( MIA_DISABLED, 0 ) );
  2211.       strcpy ( szCaptionFile, szFilename );
  2212.       pldIn = pldOut + 1;
  2213.       usLineCount--;
  2214.       for ( usDisplayLine = 0; usDisplayLine< usLineCount; usDisplayLine++ )
  2215.       {
  2216.          *pldOut = *pldIn;
  2217.          pldOut->szText[8] = CHAR_NULL;
  2218.          pldOut->ulTime    = (ULONG) atol ( (PCHAR) pldOut->szText );
  2219.          pldOut->szText   += 9;
  2220.          pldOut->lTextLen -= 9;
  2221.          pldIn++;
  2222.          pldOut++;
  2223.       }
  2224.    }
  2225.    else
  2226.    {
  2227.       bCaptionsLoaded = FALSE;
  2228.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVE,   TRUE ),
  2229.                                  MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED ) );
  2230.       WinSendMsg ( hwndMenu, MM_SETITEMATTR, MPFROM2SHORT ( IDM_SAVEAS, TRUE ),
  2231.                                  MPFROM2SHORT ( MIA_DISABLED, 0            ) );
  2232.       strcpy ( szTextFile, szFilename );
  2233.       szCaptionFile[0] = 0;
  2234.       pldOut = (PLINEDATA) pvLinedataTable;/*---------------------------------*/
  2235.       pldOut[0].ulTime = 0;                /*Mark the first line for immediate*/
  2236.                                            /*display                          */
  2237.    }                                       /*---------------------------------*/
  2238.  
  2239.    /*-------------------------------------------------------------------------*/
  2240.    /* Now set the initial caption position.  If there is an audio file loaded,*/
  2241.    /* set the position according to the position of the audio file.  If there */
  2242.    /* is no audio file loaded, just display the first line of text at the     */
  2243.    /* bottom of the text window                                               */
  2244.    /*-------------------------------------------------------------------------*/
  2245.  
  2246.    if ( iState != ST_CLOSED )
  2247.    {
  2248.       mresult =
  2249.           WinSendMsg( hwndAudioSlider, SLM_QUERYSLIDERINFO,
  2250.                       MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_RANGEVALUE), 0 );
  2251.       sArmPosition = SHORT1FROMMP ( (MPARAM) mresult );
  2252.       PositionCaptions ( sArmPosition );
  2253.    }
  2254.    else
  2255.    {
  2256.       usDisplayLine = 0;                           /*-------------------------*/
  2257.       DisplayTextLine();                           /* Display the first line  */
  2258.       WinInvalidateRect ( hwndText, NULL, FALSE ); /*-------------------------*/
  2259.       usNextline = 1;
  2260.    }
  2261.  
  2262.  
  2263. /*--- Set the Start Timing button, the Play button ---------------------------*/
  2264.  
  2265.    if ( bAudioLoaded )
  2266.    {
  2267.       WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_SET_TIMING ), TRUE );
  2268.    }
  2269.  
  2270.    if ( bCaptionsLoaded && bAudioLoaded )
  2271.       WinEnableWindow ( WinWindowFromID ( hwndMainDlg, ID_PLAY ), TRUE );
  2272.  
  2273.    return 0;
  2274. }
  2275.  
  2276.  
  2277. /******************************************************************************
  2278.  * Name         : PositionCaptions
  2279.  *
  2280.  * Description  : This function will position the captions in the caption
  2281.  *                window according to the position of the audio slider.
  2282.  *
  2283.  * Parameters   : aArmPos   -  audio slider arm position
  2284.  *
  2285.  * Return       : none.
  2286.  *
  2287.  ******************************************************************************/
  2288. VOID PositionCaptions ( SHORT sArmPos )
  2289. {
  2290.    PLINEDATA pld;
  2291.    ULONG     ulAudioPos;                        /* Audio position in MM units */
  2292.    SHORT     sLineIndex;
  2293.  
  2294.  
  2295.    if ( ! bTextLoaded ) return;
  2296.                                                   /*--------------------------*/
  2297.    WinStopTimer ( hab, hwndText, CC_TIMER_ID );   /*   Be sure to stop any    */
  2298.    usNextlineReq = 0;                             /*   scrolling in progress. */
  2299.    lScrollOffset = 0;                             /*--------------------------*/
  2300.  
  2301.    ulAudioPos = (ULONG) ( ulAudioLength * sArmPos / ( sAudioArmRange - 1 ) );
  2302.    pld        = (PLINEDATA) pvLinedataTable;
  2303.  
  2304.    for ( sLineIndex = 0; sLineIndex < (SHORT) usLineCount; sLineIndex++ )
  2305.    {
  2306.        if ( pld->ulTime == ulAudioPos ) break;  /*---------------------------*/
  2307.        if ( pld->ulTime > ulAudioPos )          /* Scan the Line Data Table  */
  2308.        {                                        /* until we reach a line     */
  2309.           sLineIndex--;                         /* to be shown at or later   */
  2310.           if ( sLineIndex < 0 ) sLineIndex = 0; /* than the current audio    */
  2311.           break;                                /* position, or until we run */
  2312.        }                                        /* off the end of the table. */
  2313.        pld++;                                   /*---------------------------*/
  2314.    }
  2315.  
  2316.    if ( sLineIndex == (SHORT) usLineCount ) sLineIndex--;
  2317.  
  2318.    if ( usDisplayLine != (USHORT) sLineIndex )
  2319.    {
  2320.       usDisplayLine     = (USHORT) sLineIndex;      /*------------------------*/
  2321.       DisplayTextLine   ();                         /*      Display the text  */
  2322.       WinInvalidateRect ( hwndText, NULL, FALSE );  /*------------------------*/
  2323.       usNextline        = usDisplayLine + 1;
  2324.    }
  2325. }
  2326.  
  2327.  
  2328. /******************************************************************************
  2329.  * Name         : DisplayTextLine
  2330.  *
  2331.  * Description  : This function will write a line of text to the backup bitmap
  2332.  *                of the text window to display it.
  2333.  *
  2334.  * Parameters   : none.
  2335.  *
  2336.  * Return       : none.
  2337.  *
  2338.  ******************************************************************************/
  2339. static VOID DisplayTextLine ( void )
  2340. {
  2341.    PLINEDATA pld;
  2342.    POINTL    ptl;
  2343.    USHORT    usTestLine;
  2344.    LONG      lLineCount;
  2345.    SHORT     sPosition;
  2346.  
  2347. /*-- Erase the pres. space and point ptl to the left end of the bottom line --*/
  2348.  
  2349.    GpiErase ( hpsText );
  2350.    pld        = (PLINEDATA) pvLinedataTable + usDisplayLine;
  2351.    ptl.x      = CC_XMARGIN;
  2352.    ptl.y      = lLastLineY;
  2353.    usTestLine = usDisplayLine;
  2354.  
  2355.  
  2356. /*----------------------------------------------------------------------------*/
  2357. /* Write lines from bottom to top until we have filled the window or run out  */
  2358. /* of lines.                                                                  */
  2359. /*----------------------------------------------------------------------------*/
  2360.  
  2361.    for ( lLineCount = 0; lLineCount < lDisplayLines; lLineCount++ )
  2362.    {
  2363.       if ( usTestLine < usLineCount )
  2364.          GpiCharStringAt ( hpsText, &ptl, pld->lTextLen, (PCH) pld->szText );
  2365.       if ( usTestLine == 0 ) break;
  2366.       ptl.y += lLineSpacing;
  2367.       pld--;
  2368.       usTestLine--;
  2369.    }
  2370. }
  2371.  
  2372.  
  2373. /******************************************************************************
  2374.  * Name         : SaveChanges
  2375.  *
  2376.  * Description  : This function will ask the user if he wants to save the
  2377.  *                changes made to the text or caption file.
  2378.  *
  2379.  * Parameters   : flStyle  - buttons style flags for the message box.
  2380.  *
  2381.  * Return       : usReturn - result of the WinMessageBox call.
  2382.  *
  2383.  ******************************************************************************/
  2384. USHORT SaveChanges ( ULONG flStyle )
  2385. {
  2386.    USHORT usReturn;
  2387.    PSZ    psz, pszSlash;
  2388.    CHAR   szMessage[100];
  2389.  
  2390.  
  2391.    WinLoadString ( hab, 0, STRID_SAVECHANGES_MESSAGE, 100,         szMessage );
  2392.  
  2393.    usReturn = WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szMessage,
  2394.                               szErrorMsgTitle, 0,
  2395.                               flStyle | MB_QUERY | MB_MOVEABLE);
  2396.  
  2397.  
  2398. /*---- If the user asks to save the file, give him a Save as dialog box ------*/
  2399.  
  2400.    if ( usReturn == MBID_YES )
  2401.    {
  2402.       if ( szCaptionFile [0] )
  2403.          FormatFname ( fdgSaveAs.szFullFile, szCaptionFile );
  2404.       else
  2405.       {
  2406.          FormatFname ( fdgSaveAs.szFullFile, szTextFile );
  2407.          psz      = (PSZ) strrchr ( fdgSaveAs.szFullFile, '.' );
  2408.          pszSlash = (PSZ) strrchr ( fdgSaveAs.szFullFile, '\\' );
  2409.          if ( pszSlash < psz )  strcpy  ( (char *)psz, "._CC" );
  2410.       }
  2411.  
  2412.       usFiledlgHelpRes = PANEL_FILEDLG_SAVEAS;
  2413.       DisplaySaveasDlg(IDM_SAVE);
  2414.    }
  2415.  
  2416.    return usReturn;
  2417. }
  2418.  
  2419.  
  2420. /******************************************************************************
  2421.  * Name         : CheckForTiming
  2422.  *
  2423.  * Description  : This function will check for untimed lines in the text file.
  2424.  *                This function is called just before a caption file is to be
  2425.  *                saved.  It scans the Line Data Table looking for lines which
  2426.  *                have been left untimed.  If an untimed line is found, the
  2427.  *                function then asks the user if he still wants to save.
  2428.  *
  2429.  * Parameters   : none.
  2430.  *
  2431.  * Return       : TRUE   -  if the file is to be saved (or if there are no
  2432.  *                          untimed lines).
  2433.  *                FALSE  -  if the user decides not to save the file.
  2434.  *
  2435.  ******************************************************************************/
  2436. BOOL CheckForTiming ( void )
  2437. {
  2438.    PLINEDATA pld;
  2439.    USHORT    usLineIndex, usReturn;
  2440.    CHAR      szError[ERROR_LENGTH];
  2441.  
  2442.    pld = (PLINEDATA) pvLinedataTable;
  2443.    for ( usLineIndex = 0; usLineIndex < usLineCount; usLineIndex++ )
  2444.    {
  2445.       if ( pld->ulTime == LINE_NOT_TIMED )
  2446.       {
  2447.          WinLoadString ( hab, 0, STRID_UNTIMED_MESSAGE, ERROR_LENGTH, szError );
  2448.  
  2449.          usReturn = WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError,
  2450.                                     szErrorMsgTitle, 0,
  2451.                                     MB_YESNO | MB_QUERY | MB_MOVEABLE);
  2452.          if ( usReturn == MBID_YES )
  2453.             return TRUE;
  2454.          else
  2455.             return FALSE;
  2456.       }
  2457.       pld++;
  2458.    }
  2459.  
  2460.    return TRUE;
  2461. }
  2462.  
  2463.  
  2464. /******************************************************************************
  2465.  * Name         : SaveCaptionFile
  2466.  *
  2467.  * Description  : This function will save the caption file that is currently
  2468.  *                loaded.
  2469.  *
  2470.  * Parameters   : szFilename  - use this file name to save
  2471.  *                sMenuItem   - menu selected like "Save" or "Save as"
  2472.  *
  2473.  * Return       : apiret   -  function return code.
  2474.  *
  2475.  ******************************************************************************/
  2476. APIRET SaveCaptionFile ( CHAR szFilename[], SHORT sMenuItem )
  2477. {
  2478.    HFILE      hfile;
  2479.    ULONG      ulAction;
  2480.    USHORT     usResponse;
  2481.    PLINEDATA  pld;
  2482.    USHORT     usLineIndex;
  2483.    CHAR       szOutput[MAX_OUTPUT_LENGTH];
  2484.    BOOL       bTruncated;
  2485.    APIRET     apiret;
  2486.    CHAR       szError[ERROR_LENGTH];
  2487.    USHORT     i;
  2488.  
  2489. /*----------------------------------------------------------------------------*/
  2490. /*                                                                            */
  2491. /*  Try to open the Caption File.  If the user is trying to "Save as..." a    */
  2492. /*  file which already exists, issue a warning and ask him if he wants to     */
  2493. /*  overwrite the file.                                                       */
  2494. /*                                                                            */
  2495. /*----------------------------------------------------------------------------*/
  2496.  
  2497.    apiret = DosOpen ( (PSZ) szFilename, &hfile, &ulAction, 0,
  2498.                       FILE_NORMAL, FILE_CREATE,
  2499.                       OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL );
  2500.  
  2501.    if ( ( apiret == ERROR_OPEN_FAILED ) &&
  2502.         ( sMenuItem == IDM_SAVE ) )
  2503.       apiret = DosOpen( (PSZ) szFilename, &hfile, &ulAction, 0,
  2504.                         FILE_NORMAL, FILE_TRUNCATE,
  2505.                         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL);
  2506.  
  2507.                                                  /* Trap overwrites for the   */
  2508.    if ( apiret == ERROR_OPEN_FAILED )            /* SAVE AS... menu item      */
  2509.    {
  2510.       WinLoadString ( hab, 0, STRID_OVERWRITE_QUERY, ERROR_LENGTH, szError );
  2511.       usResponse =
  2512.         WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szFilename,
  2513.                                    0, MB_OKCANCEL | MB_QUERY | MB_MOVEABLE);
  2514.  
  2515.       if ( usResponse == MBID_CANCEL )
  2516.       {
  2517.         /*
  2518.          * If the user select's cancel, that means he wants to retry saving
  2519.          * the file using a different name.  So, go thru the same logic
  2520.          * again.
  2521.          */
  2522.         DisplaySaveasDlg(sMenuItem);
  2523.         return apiret;
  2524.       }
  2525.       /*
  2526.        * The user's response was OK to the "overwrite" warning message.
  2527.        * Go ahead and overwrite the file.
  2528.        */
  2529.       else
  2530.       {
  2531.          apiret =
  2532.            DosOpen( (PSZ) szFilename, &hfile, &ulAction, 0,
  2533.                     FILE_NORMAL, FILE_TRUNCATE,
  2534.                     OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, NULL );
  2535.       }
  2536.    }
  2537.  
  2538.    if ( apiret )
  2539.    {
  2540.       DisplayDosError ( szErrorMsgTitle, apiret );
  2541.       return apiret;
  2542.    }
  2543.  
  2544.  
  2545. /*---------------- Write the Caption data to the file ------------------------*/
  2546.  
  2547.    bTruncated = FALSE;
  2548.  
  2549.    if ( ! ( apiret = WriteLine ( hfile, (PSZ) szCC_FILE ) ) )
  2550.    {
  2551.       pld = (PLINEDATA) pvLinedataTable;
  2552.       for ( usLineIndex = 0; usLineIndex < usLineCount; usLineIndex++ )
  2553.       {
  2554.          sprintf ( szOutput, "%08lu ", pld->ulTime );
  2555.          if ( ( pld->lTextLen + 10 ) > MAX_OUTPUT_LENGTH ) bTruncated = TRUE;
  2556.          strncat(szOutput,(char *)pld->szText,(size_t)(MAX_OUTPUT_LENGTH - 10));
  2557.          if ( apiret = WriteLine ( hfile, (PSZ) szOutput ) ) break;
  2558.          pld++;
  2559.       }
  2560.       if ( ! apiret )
  2561.       {
  2562.          apiret = DosWrite ( hfile, &cEOF, 1, &ulAction );
  2563.          if ( ! apiret && ! ulAction ) apiret = ERROR_DISK_FULL;
  2564.          if ( apiret ) DisplayDosError ( szErrorMsgTitle, apiret );
  2565.       }
  2566.    }
  2567.    DosClose ( hfile );
  2568.    if ( bTruncated )
  2569.    {
  2570.       WinLoadString ( hab, 0, STRID_TRUNCATE_WARNING, ERROR_LENGTH, szError );
  2571.       WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szFilename, 0,
  2572.                                     MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  2573.    }
  2574.    if ( ! apiret ) bUnsavedChanges = FALSE;
  2575.    return apiret;
  2576. }
  2577.  
  2578.  
  2579. /******************************************************************************
  2580.  * Name         : WriteLine
  2581.  *
  2582.  * Description  : This function will write a single line to the caption file.
  2583.  *                loaded.
  2584.  *
  2585.  * Parameters   : hfile  - Handle of output file
  2586.  *                psz    - Pointer to a NULL-terminated string to write to the
  2587.  *                         file.
  2588.  *
  2589.  * Return       : apiret -  function return code.
  2590.  *
  2591.  ******************************************************************************/
  2592. APIRET WriteLine ( HFILE hfile, PSZ psz )
  2593. {
  2594.    APIRET apiret;
  2595.    ULONG  ulBytesReq;
  2596.    ULONG  ulBytesWritten;
  2597.    CHAR   acNewline[] = { CHAR_RETURN, CHAR_LINEFEED };
  2598.  
  2599.  
  2600.    ulBytesReq = (ULONG) strlen ( (char *)psz );
  2601.    apiret = DosWrite ( hfile, psz, ulBytesReq, &ulBytesWritten );
  2602.    if ( ! apiret && ( ulBytesWritten < ulBytesReq ) ) apiret = ERROR_DISK_FULL;
  2603.    if ( ! apiret )
  2604.    {
  2605.       apiret = DosWrite ( hfile, acNewline, 2, &ulBytesWritten );
  2606.       if ( ! apiret && ( ulBytesWritten < 2 ) ) apiret = ERROR_DISK_FULL;
  2607.    }
  2608.    if ( apiret ) DisplayDosError ( szErrorMsgTitle, apiret );
  2609.    return apiret;
  2610. }
  2611.  
  2612.  
  2613. /******************************************************************************
  2614.  * Name         : DisplayDosError
  2615.  *
  2616.  * Description  : This function will display a Dos of local file error.
  2617.  *
  2618.  * Parameters   : szTitle - Error message-box title.
  2619.  *                apiret  - DOS or local error code.
  2620.  *
  2621.  * Return       : none.
  2622.  *
  2623.  ******************************************************************************/
  2624. VOID DisplayDosError ( CHAR szTitle[], APIRET apiret )
  2625. {
  2626.    CHAR  szError[ERROR_LENGTH];
  2627.    CHAR  szFormat[ERROR_LENGTH];
  2628.  
  2629.  
  2630.    switch ( apiret )
  2631.    {
  2632.       case ERROR_TEXT_FILE_FORMAT:
  2633.          WinLoadString( hab, 0, STRID_TEXT_FILE_FORMAT, ERROR_LENGTH, szError );
  2634.          break;
  2635.  
  2636.       case ERROR_TOO_MANY_LINES:
  2637.          WinLoadString ( hab, 0, STRID_TOO_MANY_LINES, ERROR_LENGTH, szError );
  2638.          break;
  2639.  
  2640.       case ERROR_UNEXPECTED_EOF:
  2641.          WinLoadString ( hab, 0, STRID_UNEXPECTED_EOF, ERROR_LENGTH, szError );
  2642.          break;
  2643.  
  2644.       case ERROR_DISK_FULL:
  2645.          WinLoadString ( hab, 0, STRID_DISK_FULL, ERROR_LENGTH, szError );
  2646.          break;
  2647.  
  2648.       case ERROR_CANNOT_FIND_TEXTFILE:
  2649.          WinLoadString ( hab, 0, STRID_CANNOT_FIND_TEXTFILE, ERROR_LENGTH, szError );
  2650.          break;
  2651.  
  2652.       default:
  2653.          WinLoadString(hab, 0, STRID_GENERIC_DOS_ERROR, ERROR_LENGTH, szError );
  2654.    }
  2655.  
  2656.    WinMessageBox ( HWND_DESKTOP, hwndMainDlg, szError, szTitle, 0,
  2657.                                                MB_OK | MB_ERROR | MB_MOVEABLE);
  2658. }
  2659.  
  2660.  
  2661. /******************************************************************************
  2662.  * Name         : ResizeTextWindow
  2663.  *
  2664.  * Description  : This function will resize an existing text window to a
  2665.  *                different number of lines selected. Also adjust the main
  2666.  *                dialog window according to the text window size.
  2667.  *
  2668.  * Parameters   : lNewDisplayLines  - Number of lines desired.
  2669.  *
  2670.  * Return       : none.
  2671.  *
  2672.  ******************************************************************************/
  2673. static VOID ResizeTextWindow ( LONG lNewDisplayLines )
  2674. {
  2675.    LONG  lWidth;
  2676.    LONG  lHeight;
  2677.    LONG  lX;
  2678.    LONG  lY;
  2679.    SWP   swpFrame;
  2680.    SWP   swpDefault;
  2681.    SWP   swpDialog;
  2682.    SWP   swpText;
  2683.    BOOL  fAtDefaultSize = FALSE;
  2684.  
  2685. /*-------- Uncheck the menu item for previous display lines ------------------*/
  2686.  
  2687.    switch ( lDisplayLines )
  2688.    {
  2689.       case 2: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2690.                                      MPFROM2SHORT ( IDM_2_LINES, TRUE ),
  2691.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2692.               break;
  2693.  
  2694.       case 3: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2695.                                      MPFROM2SHORT ( IDM_3_LINES, TRUE ),
  2696.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2697.               break;
  2698.  
  2699.       case 4: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2700.                                      MPFROM2SHORT ( IDM_4_LINES, TRUE ),
  2701.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2702.               break;
  2703.  
  2704.       case 5: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2705.                                      MPFROM2SHORT ( IDM_5_LINES, TRUE ),
  2706.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2707.               break;
  2708.  
  2709.       case 6: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2710.                                      MPFROM2SHORT ( IDM_6_LINES, TRUE ),
  2711.                                      MPFROM2SHORT ( MIA_CHECKED, 0 ) );
  2712.    }
  2713.  
  2714.  
  2715. /*-------- Check the menu item for the new display line count ----------------*/
  2716.  
  2717.    switch ( lNewDisplayLines )
  2718.    {
  2719.       case 2: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2720.                                MPFROM2SHORT ( IDM_2_LINES, TRUE ),
  2721.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2722.               break;
  2723.  
  2724.       case 3: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2725.                                MPFROM2SHORT ( IDM_3_LINES, TRUE ),
  2726.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2727.               break;
  2728.  
  2729.       case 4: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2730.                                MPFROM2SHORT ( IDM_4_LINES, TRUE ),
  2731.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2732.               break;
  2733.  
  2734.       case 5: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2735.                                MPFROM2SHORT ( IDM_5_LINES, TRUE ),
  2736.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2737.               break;
  2738.  
  2739.       case 6: WinSendMsg ( hwndMenu, MM_SETITEMATTR,
  2740.                                MPFROM2SHORT ( IDM_6_LINES, TRUE ),
  2741.                                MPFROM2SHORT ( MIA_CHECKED, MIA_CHECKED ) );
  2742.    }
  2743.  
  2744.    lDisplayLines = lNewDisplayLines;
  2745.  
  2746. /*---------------------- Resize the Window -----------------------------------*/
  2747. /*                                                                            */
  2748. /*  (1) Hide the Text window, so we don't get a WM_PAINT message while the    */
  2749. /*      backup bitmap is destroyed.                                           */
  2750. /*                                                                            */
  2751. /*  (2) Delete the present backup bitmap.                                     */
  2752. /*                                                                            */
  2753. /*  (3) Create a new backup bitmap having the desired dimensions.             */
  2754. /*                                                                            */
  2755. /*  (4) Calculate the new Text Window size.                                   */
  2756. /*                                                                            */
  2757. /*  (5) Calculate the new Main Window size.                                   */
  2758. /*                                                                            */
  2759. /*  (6) Show the new text window.                                             */
  2760. /*                                                                            */
  2761. /*----------------------------------------------------------------------------*/
  2762.  
  2763.    WinSetWindowPos( hwndText, 0, 0, 0, 0, 0, SWP_HIDE );/*(1) Hide text window*/
  2764.  
  2765.    GpiDestroyPS( hpsText );  /*-----------------------------------------------*/
  2766.    DevCloseDC  ( hdcText );  /*(2)Get rid of the old text window backup bitmap*/
  2767.    GpiDeleteBitmap( hbmText);/*-----------------------------------------------*/
  2768.  
  2769.    CreateTextBitmap ();   /* (3) Create a backup bitmap in the new dimensions */
  2770.  
  2771.    lWidth  = rclMain.xRight - 10;
  2772.    lHeight   = ( 2 * lTitleY + rclTextClient.yTop );
  2773.    lX = 5;
  2774.    lY = ( rclMain.yTop - (rclMain.yTop / 5) ) ;
  2775.  
  2776.    WinSetWindowPos( hwndText, 0, lX, lY, lWidth, lHeight, /*(4) Show new text */
  2777.                           SWP_SHOW | SWP_MOVE | SWP_SIZE );/*     window.  */
  2778.  
  2779.    WinQueryWindowPos   ( hwndMainFrame, &swpFrame ) ;      /* (5)             */
  2780.    WinQueryDefaultSize ( hwndMainFrame, &swpDefault ) ;
  2781.  
  2782.    if (swpFrame.cx==swpDefault.cx && swpFrame.cy==swpDefault.cy)
  2783.       fAtDefaultSize = TRUE;
  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.    if (fAtDefaultSize)
  2811.       WinDefaultSize( hwndMainDlg);                                /* (6)     */
  2812.    else
  2813.       WinUpdateWindow(hwndMainDlg);
  2814.  
  2815.    if ( bTextLoaded ) DisplayTextLine();
  2816.  
  2817.    WinInvalidateRect ( hwndText, 0, FALSE );
  2818. }
  2819.  
  2820.  
  2821. /******************************************************************************
  2822.  * Name         : CreateTextBitmap
  2823.  *
  2824.  * Description  : This function will create a backup bitmap for the text window.
  2825.  *
  2826.  * Parameters   : none.
  2827.  *
  2828.  * Return       : none.
  2829.  *
  2830.  ******************************************************************************/
  2831. VOID CreateTextBitmap ( void )
  2832. {
  2833.    FONTMETRICS       fmText;
  2834.    LONG              lModulo;
  2835.    SIZEL             sizelText;
  2836.    BITMAPINFOHEADER2 bmh2;
  2837.  
  2838.  
  2839. /*--- Open a memory device context and create a Micro presentation space -----*/
  2840.  
  2841.    hdcText          = DevOpenDC ( hab, OD_MEMORY, "*", 0, NULL, 0 );
  2842.  
  2843.    sizelText.cx     = 0;
  2844.    sizelText.cy     = 0;
  2845.    hpsText          = GpiCreatePS ( hab, hdcText, &sizelText,
  2846.                             PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  2847.  
  2848.  
  2849. /*------------------- Calculate bitmap height --------------------------------*/
  2850. /*                                                                            */
  2851. /*  The height of the caption window and the line spacing within the window   */
  2852. /*  both depend on the height of the font being used.  (1) We will use the    */
  2853. /*  default font for the presentation space.  (2) The line spacing (in pels)  */
  2854. /*  will be AT LEAST:                                                         */
  2855. /*                                                                            */
  2856. /*      ( Max Baseline Extent ) + ( External Leading ) + ( Scroll Increment ) */
  2857. /*                                                                            */
  2858. /*  (3) There is one further condition: the line spacing must be an integer   */
  2859. /*  multiple of the scroll increment.  If necessary, increase the above line  */
  2860. /*  spacing so that this condition is met.                                    */
  2861. /*                                                                            */
  2862. /*----------------------------------------------------------------------------*/
  2863.  
  2864.    GpiQueryFontMetrics ( hpsText, sizeof(fmText), &fmText );/*(1) default font*/
  2865.  
  2866.    lLineSpacing  = fmText.lMaxBaselineExt          /* (2) Lower limit of line */
  2867.                  + fmText.lExternalLeading         /*     spacing.            */
  2868.                  + CC_SCROLL_INC;
  2869.  
  2870.    if ( lModulo = lLineSpacing % CC_SCROLL_INC ) /* (3) Adjust spacing to int */
  2871.       lLineSpacing += CC_SCROLL_INC - lModulo;   /*     mult of scroll incr.  */
  2872.  
  2873.    rclTextClient.yTop =
  2874.           lDisplayLines * lLineSpacing;          /* Now calculate height and  */
  2875.    lLastLineY = CC_SCROLL_INC + fmText.lMaxDescender;/*position of last line. */
  2876.  
  2877.  
  2878. /*-- Create a monochrome bitmap having the dimensions we just calculated -----*/
  2879.  
  2880.    bmh2.cbFix             = sizeof (BITMAPINFOHEADER2);
  2881.    bmh2.cx                = CC_WIDTH;
  2882.    bmh2.cy                = rclTextClient.yTop;
  2883.    bmh2.cPlanes           = 1;
  2884.    bmh2.cBitCount         = 1;                 /* This is a monochrome bitmap */
  2885.    bmh2.ulCompression     = BCA_UNCOMP;
  2886.    bmh2.cbImage           = 0;
  2887.    bmh2.cxResolution      = 30000;
  2888.    bmh2.cyResolution      = 30000;
  2889.    bmh2.cclrUsed          = 2;
  2890.    bmh2.cclrImportant     = 2;
  2891.    bmh2.usUnits           = BRU_METRIC;
  2892.    bmh2.usReserved        = 0;
  2893.    bmh2.usRecording       = BRA_BOTTOMUP;
  2894.    bmh2.usRendering       = BRH_NOTHALFTONED;
  2895.    bmh2.cSize1            = 0;
  2896.    bmh2.cSize2            = 0;
  2897.    bmh2.ulColorEncoding   = BCE_RGB;
  2898.    bmh2.ulIdentifier      = 0;
  2899.    hbmText                = GpiCreateBitmap ( hpsText, &bmh2, 0L, 0L, NULL );
  2900.  
  2901.    GpiSetBitmap   ( hpsText, hbmText );  /* Set the bitmap into the pres space*/
  2902.    GpiErase       ( hpsText );           /* Erase the bitmap.                 */
  2903. }
  2904.  
  2905. /******************************************************************************
  2906.  * Name        : ProcuctDlgProc
  2907.  *
  2908.  * Description : This function controls the product information dialog box.
  2909.  *
  2910.  * Parameters  : hwnd - Handle for the Include dialog box.
  2911.  *               msg  - Message received by the dialog box.
  2912.  *               mp1  - Parameter 1 for the just received message.
  2913.  *               mp2  - Parameter 2 for the just received message.
  2914.  *
  2915.  * Return      : 0 or the result of default processing.
  2916.  *
  2917.  ******************************************************************************/
  2918. MRESULT EXPENTRY ProductDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  2919. {
  2920.    switch( msg )
  2921.    {
  2922.      case WM_INITDLG :
  2923.          /*
  2924.           * Add Default Size menu item to system menu of the secondary window.
  2925.           */
  2926.          WinInsertDefaultSize(hwnd, "~DefaultSize");
  2927.  
  2928.          break;
  2929.  
  2930.      case WM_CLOSE :
  2931.          WinDestroySecondaryWindow( hwnd );         /* Close the Dialog box.          */
  2932.          return( 0 );
  2933.          break;
  2934.  
  2935.      case WM_DESTROY:
  2936.          hwndProductInfo = 0;
  2937.          break;
  2938.  
  2939.      case WM_COMMAND :
  2940.          switch( SHORT1FROMMP( mp1 ) )
  2941.          {
  2942.             case DID_OK :
  2943.             case DID_CANCEL:
  2944.                WinDestroySecondaryWindow( hwnd );   /* Close the Dialog box.          */
  2945.                return( (MRESULT)TRUE);
  2946.             break;
  2947.          }  /* End of Command Switch */
  2948.  
  2949.    }  /* End of Switch */
  2950.  
  2951.    return( WinDefSecondaryWindowProc( hwnd, msg, mp1, mp2 ) );
  2952.  
  2953. } /* End of FileDlgProc */
  2954. /******************************************************************************
  2955.  * Name         : DisplaySaveasDlg
  2956.  *
  2957.  * Description  : This function will display the "Save as" dialog box
  2958.  *
  2959.  * Parameters   : SHORT sMenuItem - menu item that caused this action
  2960.  *
  2961.  * Return       : none.
  2962.  *
  2963.  ******************************************************************************/
  2964. VOID DisplaySaveasDlg ( SHORT sMenuItem )
  2965. {
  2966.  
  2967.     /*  (a) Ask the user for a file name.  If he responds favorably:    */
  2968.     /*  (b) Save the file.                                              */
  2969.     /*  (c) Store the name in szCaptionFile.                            */
  2970.     /*  (d) Enable the Save menu item .                                 */
  2971.  
  2972.     if (WinFileDlg(HWND_DESKTOP, hwndMainDlg, &fdgSaveAs))       /* (a) */
  2973.     {
  2974.        if ( fdgSaveAs.lReturn == DID_OK )
  2975.        {
  2976.           if ( iState == ST_PLAYING ) StopPlaying( hwndMainDlg );
  2977.           if (!SaveCaptionFile(fdgSaveAs.szFullFile,sMenuItem))  /* (b) */
  2978.           {
  2979.              strcpy(szCaptionFile,fdgSaveAs.szFullFile);         /* (c) */
  2980.              WinSendMsg ( hwndMenu, MM_SETITEMATTR,              /* (d) */
  2981.                           MPFROM2SHORT ( IDM_SAVE, TRUE ),
  2982.                           MPFROM2SHORT ( MIA_DISABLED, 0 ) );
  2983.           }
  2984.        }
  2985.     }
  2986. }
  2987.