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

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. /****************************************************************************
  12.  *
  13.  *   dialogs.c: Dialog box processing
  14.  *
  15.  *   Vidcap32 Source code
  16.  *
  17.  ***************************************************************************/
  18.  
  19. #include <windows.h>
  20. #include <windowsx.h>
  21. #include <commdlg.h>
  22. #include <mmsystem.h>
  23. #include <mmreg.h>
  24. #include <io.h>
  25. #include <fcntl.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <memory.h>
  29. #include <dos.h>
  30. #include <vfw.h>
  31.  
  32. #include "arrow.h"
  33. #include "rlmeter.h"
  34. #include "vidcap.h"
  35. #include "vidframe.h"
  36. #include "help.h"
  37.  
  38. static long GetFreeDiskSpaceInKB(LPTSTR) ;
  39. static int  CountMCIDevices(WORD) ;
  40.  
  41. BOOL FAR PASCAL MCISetupProc(HWND, unsigned, UINT, LONG);
  42.  
  43.  
  44. //--- utility functions  ---------------------------------------------------
  45.  
  46.  
  47.  
  48. /*----------------------------------------------------------------------------*\
  49. |   SmartWindowPosition (HWND hWndDlg, HWND hWndShow)
  50. |                                                                              |
  51. |   Description:                                                               |
  52. |       This function attempts to position a dialog box so that it
  53. |       does not obscure the hWndShow window. This function is
  54. |       typically called during WM_INITDIALOG processing.
  55. |                                                                              |
  56. |   Arguments:                                                                 |
  57. |       hWndDlg         handle of the soon to be displayed dialog
  58. |       hWndShow        handle of the window to keep visible
  59. |                                                                              |
  60. |   Returns:                                                                   |
  61. |       1 if the windows overlap and positions were adjusted
  62. |       0 if the windows don't overlap
  63. |                                                                              |
  64. \*----------------------------------------------------------------------------*/
  65. int SmartWindowPosition (HWND hWndDlg, HWND hWndShow)
  66. {
  67.     RECT rc, rcDlg, rcShow;
  68.     int iHeight, iWidth;
  69.     int iScreenHeight, iScreenWidth;
  70.  
  71.     GetWindowRect(hWndDlg, &rcDlg);
  72.     GetWindowRect(hWndShow, &rcShow);
  73.  
  74.     iScreenHeight = GetSystemMetrics(SM_CYSCREEN);
  75.     iScreenWidth = GetSystemMetrics(SM_CXSCREEN);
  76.  
  77.     InflateRect (&rcShow, 5, 5); // allow a small border
  78.     if (IntersectRect(&rc, &rcDlg, &rcShow)){
  79.         /* the two do intersect, now figure out where to place */
  80.         /* this dialog window.  Try to go below the Show window*/
  81.         /* first and then to the right, top and left.       */
  82.  
  83.         /* get the size of this dialog */
  84.         iHeight = rcDlg.bottom - rcDlg.top;
  85.         iWidth = rcDlg.right - rcDlg.left;
  86.  
  87.         if ((WORD)(rcShow.bottom + iHeight + 1) <  iScreenHeight){
  88.                 /* will fit on bottom, go for it */
  89.                 rc.top = rcShow.bottom + 1;
  90.                 rc.left = (((rcShow.right - rcShow.left)/2) + rcShow.left)
  91.                     - (iWidth/2);
  92.         } else if ((WORD)(rcShow.right + iWidth + 1) < iScreenWidth){
  93.                 /* will fit to right, go for it */
  94.                 rc.left = rcShow.right + 1;
  95.                 rc.top = (((rcShow.bottom - rcShow.top)/2) + rcShow.top)
  96.                 - (iHeight/2);
  97.         } else if ((WORD)(rcShow.top - iHeight - 1) > 0){
  98.                 /* will fit on top, handle that */
  99.                 rc.top = rcShow.top - iHeight - 1;
  100.                 rc.left = (((rcShow.right - rcShow.left)/2) + rcShow.left)
  101.                     - (iWidth/2);
  102.         } else if ((WORD)(rcShow.left - iWidth - 1) > 0){
  103.                 /* will fit to left, do it */
  104.                 rc.left = rcShow.left - iWidth - 1;
  105.                 rc.top = (((rcShow.bottom - rcShow.top)/2) + rcShow.top)
  106.                 - (iHeight/2);
  107.         } else {
  108.                 /* we are hosed, they cannot be placed so that there is */
  109.                 /* no overlap anywhere.  To minimize the damage just put*/
  110.                 /* the dialog in the lower left corner of the screen    */
  111.                 rc.top = (int)iScreenHeight - iHeight;
  112.                 rc.left = (int)iScreenWidth - iWidth;
  113.         }
  114.  
  115.         /* make any adjustments necessary to keep it on the screen */
  116.         if (rc.left < 0) rc.left = 0;
  117.         else if ((WORD)(rc.left + iWidth) > iScreenWidth)
  118.                 rc.left = (int)(iScreenWidth - iWidth);
  119.  
  120.         if (rc.top < 0)  rc.top = 0;
  121.         else if ((WORD)(rc.top + iHeight) > iScreenHeight)
  122.                 rc.top = (int)iScreenHeight - iHeight;
  123.  
  124.         SetWindowPos(hWndDlg, NULL, rc.left, rc.top, 0, 0,
  125.                 SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  126.         return 1;
  127.     } // if the windows overlap by default
  128.  
  129.     return 0;
  130. }
  131.  
  132. //
  133. // GetFreeDiskSpace: Function to Measure Available Disk Space
  134. //
  135. static long GetFreeDiskSpaceInKB(LPTSTR pFile)
  136. {
  137.     DWORD dwFreeClusters, dwBytesPerSector, dwSectorsPerCluster, dwClusters;
  138.     char RootName[MAX_PATH];
  139.     LPSTR ptmp;    //required arg
  140.  
  141.     // need to find path for root directory on drive containing
  142.     // this file.
  143.  
  144.     GetFullPathName(pFile, sizeof(RootName)/sizeof(RootName[0]), RootName, &ptmp);
  145.  
  146.     // truncate this to the name of the root directory (god how tedious)
  147.     if ((RootName[0] == TEXT('\\')) && (RootName[1] == TEXT('\\'))) {
  148.  
  149.         // path begins with  \\server\share\path so skip the first
  150.         // three backslashes
  151.         ptmp = &RootName[2];
  152.         while (*ptmp && (*ptmp != TEXT('\\'))) {
  153.             ptmp++;
  154.         }
  155.         if (*ptmp) {
  156.             // advance past the third backslash
  157.             ptmp++;
  158.         }
  159.     } else {
  160.         // path must be drv:\path
  161.         ptmp = RootName;
  162.     }
  163.  
  164.     // find next backslash and put a null after it
  165.     while (*ptmp && (*ptmp != TEXT('\\'))) {
  166.         ptmp++;
  167.     }
  168.     // found a backslash ?
  169.     if (*ptmp) {
  170.         // skip it and insert null
  171.         ptmp++;
  172.         *ptmp = TEXT('\0');
  173.     }
  174.  
  175.  
  176.  
  177.     if (!GetDiskFreeSpace(RootName,
  178.         &dwSectorsPerCluster,
  179.         &dwBytesPerSector,
  180.         &dwFreeClusters,
  181.         &dwClusters)) {
  182.         MessageBoxID(IDS_ERR_MEASUREFREEDISK, MB_OK | MB_ICONINFORMATION);
  183.         return (-1);
  184.     }
  185.     return(MulDiv (dwSectorsPerCluster * dwBytesPerSector,
  186.            dwFreeClusters,
  187.            1024));
  188. }
  189.  
  190. //
  191. // CountMCIDevices: Function to Find the Number of MCI Devices of a Type
  192. //
  193. static int CountMCIDevices(WORD wType)
  194. {
  195.     int               nTotal = 0 ;
  196.     DWORD             dwCount ;
  197.     MCI_SYSINFO_PARMS mciSIP ;
  198.  
  199.     mciSIP.dwCallback = 0 ;
  200.     mciSIP.lpstrReturn = (LPSTR)(LPVOID) &dwCount ;
  201.     mciSIP.dwRetSize = sizeof(DWORD) ;
  202.     mciSIP.wDeviceType = wType ;
  203.  
  204.     // Use an MCI command to get the info
  205.     if (! mciSendCommand(0, MCI_SYSINFO, MCI_SYSINFO_QUANTITY,
  206.                          (DWORD)(LPVOID) &mciSIP))
  207.         nTotal = (int) *((LPDWORD) mciSIP.lpstrReturn) ;
  208.  
  209.     return nTotal ;
  210. }
  211.  
  212.  
  213.  
  214. /* lMicroSec = StringRateToMicroSec(szRate)
  215.  *
  216.  * Convert <szRate> (e.g. "3.75" representing 3.75 frames per second)
  217.  * to microseconds (e.g. 266667L microseconds per frame).
  218.  *
  219.  * If the rate is close to zero or negative, then 0L is returned.
  220.  */
  221. DWORD StringRateToMicroSec(PSTR szRate)
  222. {
  223.     double        dRate;
  224.  
  225.     dRate = atof(szRate);
  226.     
  227.     if (dRate < 0.0001) {
  228.         return 0L;
  229.     } else {
  230.         return (DWORD) /*floor*/((1e6 / dRate) + 0.5);
  231.         }
  232. }
  233.  
  234. /* ach = MicroSecToStringRate(achRate, lMicroSec)
  235.  *
  236.  * Convert <lMicroSec> (e.g. 266667L microseconds per frame) to a
  237.  * string rate (e.g. "3.75" representing 3.75 frames per second).
  238.  * Returns <achRate>.
  239.  */
  240. PSTR MicroSecToStringRate(PSTR achRate, DWORD dwMicroSec)
  241. {
  242.     sprintf(achRate, "%.3f",
  243.         (dwMicroSec == 0L) ? 0.0 : (1e6 / (double) dwMicroSec));
  244.  
  245.     return achRate;
  246. }
  247.  
  248. /*
  249.  * update the text of an edit field based on a comarrow up or down change
  250.  * - write the text in N.NNN format (truncated to an integer)
  251.  */
  252. LONG FAR PASCAL
  253. MilliSecVarArrowEditChange(
  254.     HWND hwndEdit,
  255.     UINT uCode,
  256.     LONG lMin,
  257.     LONG lMax,
  258.     UINT uInc
  259. )
  260. {
  261.     char achTemp[32];
  262.     LONG l;
  263.  
  264.     GetWindowText(hwndEdit, achTemp, sizeof(achTemp));
  265.  
  266.     l = atol(achTemp);
  267.     if(uCode == SB_LINEUP ) {
  268.  
  269.     if(l + (long)uInc <= lMax ) {
  270.         l += uInc;
  271.         wsprintf(achTemp, "%ld.000", l );
  272.         SetWindowText(hwndEdit, achTemp );
  273.         } else {
  274.         MessageBeep( 0 );
  275.     }
  276.     } else if (uCode == SB_LINEDOWN ) {
  277.     if( l-(long)uInc >= lMin ) {
  278.         l -= uInc;
  279.         wsprintf( achTemp, "%ld.000", l );
  280.         SetWindowText( hwndEdit, achTemp );
  281.         } else {
  282.         MessageBeep( 0 );
  283.     }
  284.     }
  285.     return( l );
  286. }
  287.  
  288.  
  289. BOOL MCIGetDeviceNameAndIndex (HWND hwnd, LPINT lpnIndex, LPSTR lpName)
  290. {
  291.     HWND hwndCB;
  292.     char buf[160];
  293.     char *cp;
  294.  
  295.     hwndCB = GetDlgItem( hwnd, IDD_MCI_SOURCE );
  296.     *lpnIndex = (int)SendMessage( hwndCB, CB_GETCURSEL, 0, 0L);
  297.     SendMessage( hwndCB, CB_GETLBTEXT, *lpnIndex,
  298.             (LONG)(LPSTR) buf );
  299.     // Point cp to the system name
  300.     for (cp = buf + lstrlen(buf); cp > buf; cp--) {
  301.         if (*cp == ' ' && *(cp-1) == ',') {
  302.             cp++;
  303.             break;
  304.     }
  305.     }
  306.     lstrcpy (lpName, cp);
  307.     return TRUE;
  308. }
  309.  
  310.  
  311. /*--------------------------------------------------------------+
  312. | TimeMSToHMSString() - change milliseconds into a time string   |
  313. +--------------------------------------------------------------*/
  314. void FAR PASCAL TimeMSToHMSString (DWORD dwMS, LPSTR lpTime)
  315. {
  316.     DWORD    dwTotalSecs;
  317.     LONG    lHundredths;
  318.     WORD    wSecs;
  319.     WORD    wMins;
  320.     WORD    wHours;
  321.  
  322.     /* convert to number of seconds */
  323.     dwTotalSecs = dwMS / 1000;
  324.     
  325.     /* keep the remainder part */
  326.     lHundredths = (dwMS - (dwTotalSecs * 1000)) / 10;
  327.         
  328.     /* break down into other components */
  329.     wHours = (WORD)(dwTotalSecs / 3600);    // get # Hours
  330.     dwTotalSecs -= (wHours * 3600);
  331.     
  332.     wMins = (WORD)(dwTotalSecs / 60);    // get # Mins
  333.     dwTotalSecs -= (wMins * 60);
  334.     
  335.     wSecs = (WORD)dwTotalSecs;    // what's left is # seconds
  336.     
  337.     /* build the string */
  338.     wsprintf((char far *)lpTime, "%02u:%02u:%02u.%02lu", wHours, wMins,
  339.             wSecs, lHundredths);
  340. }
  341.  
  342.  
  343. /*--------------------------------------------------------------+
  344. | TimeHMSStringToMS() - change Time string to milliseconds     |
  345. |                       returns dwMilliseconds or -1 if error  |
  346. +--------------------------------------------------------------*/
  347. LONG NEAR PASCAL  TimeHMSStringToMS (LPSTR lpsz)
  348. {
  349.     char    achTime[12];    // buffer for time string (input)
  350.     DWORD    dwMSecs;    // total MSecs for this thing */
  351.     char    *pDelim;    // pointer to next delimeter
  352.     char    *p;        // general pointer
  353.     DWORD    dwHours = 0;    // # of hours
  354.     DWORD    dwMins = 0;    // # of minutes
  355.     DWORD    dwSecs = 0;        // # of seconds
  356.     WORD    wHundredths = 0;    // # hundredths
  357.  
  358.     _fstrncpy(achTime, lpsz, sizeof (achTime));
  359.  
  360.     if (achTime[0] == '\0')
  361.         return -1;    // bad char so error out
  362.         
  363.     /* rip through the whole string and look for illegal chars */
  364.     for (p = achTime; *p ; p++){
  365.         if (!isdigit(*p) && *p != '.' && *p != ':')
  366.         return -1;    // bad char so error out
  367.     }
  368.  
  369.     /* go find the hundredths portion if it exists */
  370.     pDelim = strchr(achTime, '.');
  371.     if (*pDelim){
  372.         p = strrchr(achTime, '.');
  373.         if (pDelim != p) {
  374.             return -1;        // string has > 1 '.', return error
  375.         }
  376.  
  377.         p++;            // move up past delim
  378.         if (strlen(p) > 2) {
  379.             *(p+2) = '\0';        // knock off all but hundredths
  380.         }
  381.  
  382.         wHundredths = atoi(p);    // get the fractional part
  383.  
  384.         *pDelim = '\0';        // null out this terminator
  385.     }
  386.  
  387.     /* try and find seconds */
  388.     pDelim = strrchr(achTime, ':');    // get last ':'
  389.     if (*pDelim) {
  390.         p = (pDelim+1);
  391.     } else {
  392.         // no colon - assume just seconds in string
  393.         p = achTime;
  394.     }
  395.     dwSecs = atoi(p);
  396.  
  397.     if (*pDelim) {
  398.         *pDelim = '\0';
  399.  
  400.         /* go and get the minutes part */
  401.         pDelim = strrchr(achTime, ':');
  402.         if (*pDelim) {
  403.             p = (pDelim + 1);
  404.         } else {
  405.             // no more colons - assume remainder is just minutes
  406.             p = achTime;
  407.         }
  408.         dwMins = atoi(p);
  409.  
  410.         if (*pDelim) {
  411.             *pDelim = '\0';
  412.  
  413.             /* get the hours */
  414.             p = achTime;
  415.             dwHours = atoi(p);
  416.         }
  417.     }
  418.  
  419.     /* now we've got the hours, minutes, seconds and any    */
  420.     /* fractional part.  Time to build up the total time    */
  421.  
  422.     dwSecs += (dwHours * 3600);    // add in hours worth of seconds
  423.     dwSecs += (dwMins * 60);    // add in minutes worth of seconds
  424.     dwMSecs = (dwSecs * 1000L);
  425.     dwMSecs += (wHundredths * 10L);
  426.  
  427.     /* now we've got the total number of milliseconds */
  428.     return dwMSecs;
  429. }
  430.  
  431.  
  432. /*
  433.  *  MCIDeviceClose
  434.  *      This routine closes the open MCI device.
  435.  */
  436.  
  437. void MCIDeviceClose (void)
  438. {
  439.     mciSendString( "close mciframes", NULL, 0, NULL );
  440. }
  441.  
  442.  
  443.  
  444. /*
  445.  *  MCIDeviceOpen
  446.  *      This routine opens the mci device for use, and sets the
  447.  *      time format to milliseconds.
  448.  *      Return FALSE on error;
  449.  */
  450.  
  451. BOOL MCIDeviceOpen (LPSTR lpDevName)
  452. {
  453.     char        ach[160];
  454.     DWORD dwMCIError;
  455.  
  456.     wsprintf( ach, "open %s shareable wait alias mciframes", (LPSTR) lpDevName);
  457.     dwMCIError = mciSendString( ach, NULL, 0, NULL );
  458.     if( dwMCIError )  {
  459.         return(FALSE);
  460.     }
  461.  
  462.     dwMCIError = mciSendString( "set mciframes time format milliseconds",
  463.         NULL, 0, NULL );
  464.     if( dwMCIError ) {
  465.         MCIDeviceClose();
  466.         return(FALSE);
  467.     }
  468.     return ( TRUE );
  469.  
  470. }
  471.  
  472.  
  473. /*
  474.  *  MCIDeviceGetPosition
  475.  *      Stores the current device position in milliseconds in lpdwPos.
  476.  *      Returns TRUE on success, FALSE if error.
  477.  */
  478. BOOL FAR PASCAL MCIDeviceGetPosition (LPDWORD lpdwPos)
  479. {
  480.     char        ach[80];
  481.     DWORD dwMCIError;
  482.  
  483.     dwMCIError = mciSendString( "status mciframes position wait",
  484.         ach, sizeof(ach), NULL );
  485.     if( dwMCIError ) {
  486.         *lpdwPos = 0L;
  487.         return FALSE;
  488.     }
  489.  
  490.     *lpdwPos = atol( ach );
  491.     return TRUE;
  492. }
  493.  
  494. #ifndef USE_ACM
  495.  
  496. // --- audio streaming ------------------------------------------------
  497.  
  498. // the ShowLevel dialog streams data in from the input and
  499. // shows the current volume.
  500.  
  501. // buffers into which sound data is recorded
  502. #define NUM_LEVEL_BUFFERS   2
  503.  
  504. // the buffer size is calculated to be about 1/20 sec
  505. #define UPDATES_PER_SEC     20
  506.  
  507. /*
  508.  * we save all our data in one of these, and write a pointer to it
  509.  * into the dialog DWL_USER field.
  510.  */
  511.  
  512. typedef struct _LevelStreamData {
  513.     LPWAVEHDR alpWave[NUM_LEVEL_BUFFERS];
  514.     PCMWAVEFORMAT FAR * pwf;
  515.     HWAVEIN hwav;
  516.     int buffersize;
  517. } LEVELSTREAMDATA, FAR * PLEVELSTREAMDATA;
  518.  
  519.  
  520. //open the wave-device in the given format, queue all the buffers and
  521. //start data streaming. Save the wavein device to the dialog DWL_USER window
  522. //data area so we can close it on dialog dismissal.
  523. BOOL
  524. OpenStream(HWND hDlg, PCMWAVEFORMAT FAR * pwf)
  525. {
  526.     PLEVELSTREAMDATA pInfo;
  527.     int i;
  528.  
  529.  
  530.     pInfo = (PLEVELSTREAMDATA) GlobalLock(GlobalAlloc(GHND, sizeof(LEVELSTREAMDATA)));
  531.  
  532.     if (pInfo == NULL) {
  533.         return(FALSE);
  534.     }
  535.  
  536.  
  537.     // complete remaining areas of wf
  538.     pwf->wf.wFormatTag = WAVE_FORMAT_PCM;
  539.     pwf->wf.nBlockAlign = pwf->wf.nChannels * pwf->wBitsPerSample / 8;
  540.     pwf->wf.nAvgBytesPerSec = pwf->wf.nSamplesPerSec * pwf->wf.nBlockAlign;
  541.  
  542.     // save for later use
  543.     pInfo->pwf = pwf;
  544.  
  545.     // buffer size a fixed fraction of a second
  546.     pInfo->buffersize = pwf->wf.nAvgBytesPerSec/UPDATES_PER_SEC;
  547.  
  548.  
  549.     pInfo->hwav = NULL;
  550.  
  551.     if (waveInOpen(
  552.         &pInfo->hwav,
  553.         WAVE_MAPPER,
  554.         (LPWAVEFORMATEX)pwf,
  555.         (DWORD) hDlg,               // callback via MM_WIM_ messages to dialogproc
  556.         0,
  557.         CALLBACK_WINDOW)) {
  558.             SetWindowLong(hDlg, DWL_USER, 0);
  559.             return(FALSE);
  560.     }
  561.  
  562.     // store the info structure in the dialog, so that even if we fail
  563.     // on this routine we will clean up correctly
  564.     SetWindowLong(hDlg, DWL_USER, (long) pInfo);
  565.  
  566.     // set all the wave headers to null (for cleanup if error)
  567.     for (i = 0; i < NUM_LEVEL_BUFFERS; i++) {
  568.         pInfo->alpWave[i] = NULL;
  569.     }
  570.  
  571.     // alloc, prepare and add all the buffers
  572.     for (i = 0; i < NUM_LEVEL_BUFFERS; i++) {
  573.  
  574.         pInfo->alpWave[i] = GlobalLock(GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,
  575.                         sizeof(WAVEHDR) + pInfo->buffersize));
  576.         if (pInfo->alpWave[i] == NULL) {
  577.             return(FALSE);
  578.         }
  579.  
  580.         pInfo->alpWave[i]->lpData = (LPBYTE) (pInfo->alpWave[i] + 1);
  581.         pInfo->alpWave[i]->dwBufferLength = pInfo->buffersize;
  582.         pInfo->alpWave[i]->dwBytesRecorded = 0;
  583.         pInfo->alpWave[i]->dwUser = 0;
  584.         pInfo->alpWave[i]->dwFlags = 0;
  585.         pInfo->alpWave[i]->dwLoops = 0;
  586.  
  587.         if (waveInPrepareHeader(pInfo->hwav, pInfo->alpWave[i], sizeof(WAVEHDR))) {
  588.             return(FALSE);
  589.         }
  590.  
  591.         if (waveInAddBuffer(pInfo->hwav, pInfo->alpWave[i], sizeof(WAVEHDR))) {
  592.             return(FALSE);
  593.         }
  594.     }
  595.  
  596.     waveInStart(pInfo->hwav);
  597.  
  598.     return(TRUE);
  599. }
  600.  
  601. // terminate the data streaming on a wavein device associated with a
  602. // dialog, and clean up the buffers allocated
  603. void
  604. CloseStream(HWND hDlg)
  605. {
  606.     PLEVELSTREAMDATA pInfo;
  607.     int i;
  608.  
  609.  
  610.     // pick up our info from the dialog
  611.     pInfo = (PLEVELSTREAMDATA) GetWindowLong(hDlg, DWL_USER);
  612.     if ((pInfo == NULL) || (pInfo->hwav == NULL)) {
  613.         return;
  614.     }
  615.  
  616.     // stop streaming data
  617.     waveInStop(pInfo->hwav);
  618.  
  619.     // release all buffers
  620.     waveInReset(pInfo->hwav);
  621.  
  622.     // unlock and free buffers
  623.     for (i = 0; i < NUM_LEVEL_BUFFERS; i++) {
  624.         if (pInfo->alpWave[i]) {
  625.             waveInUnprepareHeader(pInfo->hwav, pInfo->alpWave[i], sizeof(WAVEHDR));
  626.             GlobalFree(GlobalHandle(pInfo->alpWave[i]));
  627.             pInfo->alpWave[i] = NULL;
  628.         }
  629.  
  630.     }
  631.     waveInClose(pInfo->hwav);
  632.  
  633.     GlobalFree(GlobalHandle(pInfo));
  634.  
  635.     SetWindowLong(hDlg, DWL_USER, 0);
  636.  
  637.  
  638. }
  639.  
  640. // we have received a block of data. work out the level(s) and send to
  641. // the appropriate control on the dialog, and then requeue the buffer.
  642. // return FALSE if any error occurs, otherwise TRUE
  643. BOOL
  644. StreamData(HWND hDlg, HWAVEIN hwav, LPWAVEHDR pHdr)
  645. {
  646.     PLEVELSTREAMDATA pInfo;
  647.     int n = 0;
  648.     int LevelLeft = 0, LevelRight = 0;
  649.     int i, l;
  650.  
  651.     // pick up our info from the dialog
  652.     pInfo = (PLEVELSTREAMDATA) GetWindowLong(hDlg, DWL_USER);
  653.     if ((pInfo == NULL) || (pInfo->hwav != hwav)) {
  654.         return FALSE;
  655.     }
  656.  
  657.     // go through all samples in buffer looking for maximum absolute level
  658.     while (n < pInfo->buffersize) {
  659.  
  660.         /*
  661.          * volumes go above and below the mean level - we are
  662.          * interested in the absolute volume
  663.          * 8 bit samples are in the range 0..255
  664.          * 16-bit samples are in the range -32768..+32767
  665.          */
  666.  
  667.         // skip the first byte if 16-bit
  668.         // and adjust to be in range -127..+128
  669.         if (pInfo->pwf->wBitsPerSample == 16) {
  670.             n++;
  671.             i = (int) (signed char) pHdr->lpData[n];
  672.         } else {
  673.             i = (int) ((unsigned char) pHdr->lpData[n]) - 128;
  674.         }
  675.  
  676.         // skip past the byte we've picked up
  677.         n++;
  678.  
  679.         // take absolute volume level
  680.         if (i < 0) {
  681.             i = -i;
  682.         }
  683.  
  684.         // convert to percentage
  685.         l = (i*100) / 128;
  686.  
  687.         // compare against current max
  688.         if (LevelLeft < l) {
  689.             LevelLeft = l;
  690.         }
  691.  
  692.  
  693.         // if stereo, repeat for right channel
  694.         if (pInfo->pwf->wf.nChannels == 2) {
  695.             // skip the first byte if 16-bit
  696.             if (pInfo->pwf->wBitsPerSample == 16) {
  697.                 n++;
  698.                 i = (int) (signed char) pHdr->lpData[n];
  699.             } else {
  700.                 i = (int) ((unsigned char) pHdr->lpData[n]) - 128;
  701.             }
  702.  
  703.             // skip past the byte we've picked up
  704.             n++;
  705.  
  706.             // take absolute volume level
  707.             if (i < 0) {
  708.                 i = -i;
  709.             }
  710.  
  711.             // convert to percentage
  712.             l = (i*100) / 128;
  713.  
  714.             // compare against current max
  715.             if (LevelRight < l) {
  716.                 LevelRight = l;
  717.             }
  718.         }
  719.     }
  720.  
  721.     // put the buffer back on the queue
  722.     if (waveInAddBuffer(pInfo->hwav, pHdr, sizeof(WAVEHDR))) {
  723.         return(FALSE);
  724.     }
  725.  
  726.     // send new level to dialog control
  727.     SendDlgItemMessage(hDlg, IDRL_LEVEL1, WMRL_SETLEVEL, 0, LevelLeft);
  728.     if (pInfo->pwf->wf.nChannels == 2) {
  729.         SendDlgItemMessage(hDlg, IDRL_LEVEL2, WMRL_SETLEVEL, 0, LevelRight);
  730.     }
  731.  
  732.     return(TRUE);
  733. }
  734.  
  735. #endif  // ! USE_ACM
  736.  
  737.  
  738. // --- dialog procs -----------------------------------------------------
  739.  
  740.  
  741. //
  742. // AboutProc: About Dialog Box Procedure
  743. //
  744. int FAR PASCAL AboutProc(HWND hDlg, UINT Message, UINT wParam, LONG lParam)
  745. {
  746.     switch (Message) {
  747.         case WM_INITDIALOG :
  748.              return TRUE ;
  749.  
  750.         case WM_COMMAND :
  751.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  752.                 case IDOK :
  753.                     EndDialog(hDlg, TRUE) ;
  754.                     return TRUE ;
  755.  
  756.                 case IDCANCEL :
  757.                     EndDialog(hDlg, FALSE) ;
  758.                     return TRUE ;
  759.             }
  760.             break ;
  761.     }
  762.  
  763.     return FALSE ;
  764. }
  765.  
  766. #ifndef USE_ACM
  767.  
  768. /*
  769.  * dialog proc for IDD_RECLVLMONO and IDD_RECLVLSTEREO - show current
  770.  * volume level
  771.  */
  772. int FAR PASCAL
  773. ShowLevelProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  774. {
  775.     switch(message) {
  776.  
  777.     case WM_INITDIALOG:
  778.         if (!OpenStream(hDlg, (PCMWAVEFORMAT FAR *) lParam)) {
  779.             MessageBoxID(IDS_ERR_ACCESS_SOUNDDRIVER, MB_OK|MB_ICONSTOP);
  780.             EndDialog(hDlg, FALSE);
  781.         }
  782.         return(TRUE);
  783.  
  784.     case WM_COMMAND:
  785.         switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  786.         case IDOK:
  787.         case IDCANCEL:
  788.  
  789.             CloseStream(hDlg);
  790.             EndDialog(hDlg, TRUE);
  791.             return(TRUE);
  792.         }
  793.         break;
  794.  
  795.     case MM_WIM_DATA:
  796.         if (!StreamData(hDlg, (HWAVEIN)wParam, (LPWAVEHDR)lParam)) {
  797.             MessageBoxID(IDS_ERR_ACCESS_SOUNDDRIVER, MB_OK|MB_ICONSTOP);
  798.             CloseStream(hDlg);
  799.             EndDialog(hDlg, FALSE);
  800.         }
  801.         return(TRUE);
  802.  
  803.     }
  804.     return FALSE;
  805. }
  806.  
  807.  
  808.  
  809.  
  810.  
  811. //
  812. // AudioFormatProc: Audio Format Setting Dialog Box Procedure
  813. //
  814. int FAR PASCAL AudioFormatProc(HWND hDlg, UINT Message, UINT wParam, LONG lParam)
  815. {
  816.     static int                nChannels ;
  817.     static WORD               wSample ;
  818.     static DWORD              dwFrequency ;
  819.  
  820.     switch (Message) {
  821.         case WM_INITDIALOG :
  822.             nChannels = IDD_ChannelIDs + glpwfex->nChannels ;
  823.             CheckRadioButton(hDlg, IDD_ChannelMono, IDD_ChannelStereo, nChannels) ;
  824.             wSample = IDD_SampleIDs + glpwfex->wBitsPerSample / 8 ;
  825.             CheckRadioButton(hDlg, IDD_Sample8Bit, IDD_Sample16Bit, wSample) ;
  826.             dwFrequency = IDD_FreqIDs + glpwfex->nSamplesPerSec / 11025 ;
  827.             CheckRadioButton(hDlg, IDD_Freq11kHz, IDD_Freq44kHz, (WORD)dwFrequency) ;
  828.             return TRUE ;
  829.  
  830.         case WM_COMMAND :
  831.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  832.                 case IDD_SetLevel:
  833.                 {
  834.                     // get the current data into a PCMWAVEFORMAT struct,
  835.                     // and run the ShowLevel dialog
  836.                     PCMWAVEFORMAT wf;
  837.                     UINT dlgid;
  838.  
  839.                     if (IsDlgButtonChecked(hDlg, IDD_ChannelMono)) {
  840.                         wf.wf.nChannels = 1;
  841.                         dlgid = IDD_RECLVLMONO;
  842.                     } else {
  843.                         wf.wf.nChannels = 2;
  844.                         dlgid = IDD_RECLVLSTEREO;
  845.                     }
  846.  
  847.                     if (IsDlgButtonChecked(hDlg, IDD_Sample8Bit)) {
  848.                         wf.wBitsPerSample = 8;
  849.                     } else {
  850.                         wf.wBitsPerSample = 16;
  851.                     }
  852.  
  853.                     if (IsDlgButtonChecked(hDlg, IDD_Freq11kHz)) {
  854.                         wf.wf.nSamplesPerSec = 11025 ;
  855.                     } else if (IsDlgButtonChecked(hDlg, IDD_Freq22kHz)) {
  856.                         wf.wf.nSamplesPerSec = 22050 ;
  857.                     } else {
  858.                         wf.wf.nSamplesPerSec =  44100 ;
  859.                     }
  860.  
  861.                     DoDialog(
  862.                         hDlg,
  863.                         dlgid,
  864.                         ShowLevelProc,
  865.                         (LPARAM) &wf);
  866.                     break;
  867.                 }
  868.  
  869.                 case IDOK :
  870.                     if (IsDlgButtonChecked(hDlg, IDD_ChannelMono))
  871.                         nChannels = 1 ;
  872.                     else
  873.                         if (IsDlgButtonChecked(hDlg, IDD_ChannelStereo))
  874.                             nChannels = 2 ;
  875.                         else {
  876.                             MessageBeep(MB_ICONEXCLAMATION) ;
  877.                             return FALSE ;
  878.                         }
  879.  
  880.                     if (IsDlgButtonChecked(hDlg, IDD_Sample8Bit))
  881.                         wSample = 8 ;
  882.                     else
  883.                         if (IsDlgButtonChecked(hDlg, IDD_Sample16Bit))
  884.                             wSample = 16 ;
  885.                         else {
  886.                             MessageBeep(MB_ICONEXCLAMATION) ;
  887.                             return FALSE ;
  888.                         }
  889.  
  890.                     if (IsDlgButtonChecked(hDlg, IDD_Freq11kHz))
  891.                         dwFrequency = 11025 ;
  892.                     else
  893.                         if (IsDlgButtonChecked(hDlg, IDD_Freq22kHz))
  894.                             dwFrequency = 22050 ;
  895.                         else
  896.                             if (IsDlgButtonChecked(hDlg, IDD_Freq44kHz))
  897.                                 dwFrequency = 44100 ;
  898.                             else {
  899.                                 MessageBeep(MB_ICONEXCLAMATION) ;
  900.                                 return FALSE ;
  901.                             }
  902.  
  903.                     // All the entries verfied OK -- save them now
  904.                     glpwfex->nChannels = nChannels ;
  905.                     glpwfex->wBitsPerSample = wSample ;
  906.                     glpwfex->nSamplesPerSec = dwFrequency ;
  907.                     glpwfex->nBlockAlign =  glpwfex->nChannels * (glpwfex->wBitsPerSample / 8) ;
  908.                     glpwfex->nAvgBytesPerSec = (long) glpwfex->nSamplesPerSec *
  909.                                                       glpwfex->nBlockAlign ;
  910.                     glpwfex->cbSize = 0 ;
  911.                     glpwfex->wFormatTag = WAVE_FORMAT_PCM ;
  912.                     EndDialog(hDlg, TRUE) ;
  913.                     return TRUE ;
  914.  
  915.                 case IDCANCEL :
  916.                     EndDialog(hDlg, FALSE) ;
  917.                     return TRUE ;
  918.             }
  919.             break ;
  920.     }
  921.  
  922.     return FALSE ;
  923. }
  924.  
  925. #endif // ! USE_ACM
  926.  
  927. //
  928. // AllocCapFileProc: Capture file Space Allocation Dialog Box Procedure
  929. //
  930. int FAR PASCAL AllocCapFileProc(HWND hDlg, UINT Message, UINT wParam, LONG lParam)
  931. {
  932.     static int      nFreeMBs = 0 ;
  933.  
  934.     switch (Message) {
  935.         case WM_INITDIALOG :
  936.         {
  937.             int              fh ;
  938.             long             lFileSize = 0 ;
  939.             long             lFreeSpaceInKB ;
  940.             TCHAR         achCapFile[_MAX_PATH] ;
  941.  
  942.             // Get current capture file name and measure its size
  943.             capFileGetCaptureFile(ghWndCap, achCapFile, sizeof(achCapFile) / sizeof(TCHAR)) ;
  944.             if ((fh = _open(achCapFile, _O_RDONLY)) != -1) {
  945.                 if ((lFileSize = _lseek(fh, 0L, SEEK_END)) == -1L) {
  946.                     MessageBoxID(IDS_ERR_SIZECAPFILE,
  947.                     MB_OK | MB_ICONEXCLAMATION) ;
  948.                     lFileSize = 0 ;
  949.                 }
  950.                 _close(fh) ;
  951.             }
  952.  
  953.             // Get free disk space and add current capture file size to that.
  954.             // Convert the available space to MBs.
  955.             if ((lFreeSpaceInKB = GetFreeDiskSpaceInKB(achCapFile)) != -1L) {
  956.                 lFreeSpaceInKB += lFileSize / 1024 ;
  957.                 nFreeMBs = lFreeSpaceInKB / 1024 ;
  958.                 SetDlgItemInt(hDlg, IDD_SetCapFileFree, nFreeMBs, TRUE) ;
  959.             } else {
  960.  
  961.                 EnableWindow(GetDlgItem(hDlg, IDD_SetCapFileFree), FALSE);
  962.  
  963.             }
  964.  
  965.             gwCapFileSize = (WORD) (lFileSize / ONEMEG);
  966.  
  967.             SetDlgItemInt(hDlg, IDD_SetCapFileSize, gwCapFileSize, TRUE) ;
  968.             return TRUE ;
  969.         }
  970.  
  971.         case WM_COMMAND :
  972.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  973.                 case IDOK :
  974.                 {
  975.                     int         iCapFileSize ;
  976.  
  977.                     iCapFileSize = (int) GetDlgItemInt(hDlg, IDD_SetCapFileSize, NULL, TRUE) ;
  978.                     if (iCapFileSize <= 0 || iCapFileSize > nFreeMBs) {
  979.                         // You are asking for more than we have !! Sorry, ...
  980.                         SetDlgItemInt(hDlg, IDD_SetCapFileSize, iCapFileSize, TRUE) ;
  981.                         SetFocus(GetDlgItem(hDlg, IDD_SetCapFileSize)) ;
  982.                         MessageBeep(MB_ICONEXCLAMATION) ;
  983.                         return FALSE ;
  984.                     }
  985.                     gwCapFileSize = iCapFileSize ;
  986.  
  987.                     EndDialog(hDlg, TRUE) ;
  988.                     return TRUE ;
  989.                 }
  990.  
  991.                 case IDCANCEL :
  992.                     EndDialog(hDlg, FALSE) ;
  993.                     return TRUE ;
  994.  
  995.                 case IDD_SetCapFileSize:
  996.                 {
  997.                     long l;
  998.                     BOOL bchanged;
  999.                     char achBuffer[21];
  1000.  
  1001.                     // check that entered size is a valid number
  1002.                     GetDlgItemText(hDlg, IDD_SetCapFileSize, achBuffer, sizeof(achBuffer));
  1003.                     l = atol(achBuffer);
  1004.                     bchanged = FALSE;
  1005.                     if (l < 1) {
  1006.                         l = 1;
  1007.                         bchanged = TRUE;
  1008.                     } else if (l > nFreeMBs) {
  1009.                         l = nFreeMBs;
  1010.                         bchanged = TRUE;
  1011.                     } else {
  1012.                         // make sure there are no non-digit chars
  1013.                         // atol() will ignore trailing non-digit characters
  1014.                         int c = 0;
  1015.                         while (achBuffer[c]) {
  1016.                             if (IsCharAlpha(achBuffer[c]) ||
  1017.                                 !IsCharAlphaNumeric(achBuffer[c])) {
  1018.  
  1019.                                 // string contains non-digit chars - reset
  1020.                                 l = 1;
  1021.                                 bchanged = TRUE;
  1022.                                 break;
  1023.                             }
  1024.                             c++;
  1025.                         }
  1026.                     }
  1027.                     if (bchanged) {
  1028.                         wsprintf(achBuffer, "%ld", l);
  1029.                         SetDlgItemText(hDlg, IDD_SetCapFileSize, achBuffer);
  1030.                     }
  1031.                     break;
  1032.                 }
  1033.             }
  1034.             break ;
  1035.     }
  1036.  
  1037.     return FALSE ;
  1038.  
  1039. }
  1040.  
  1041. #if 0
  1042. //
  1043. // MakePaletteProc: Palette Details Dialog Box Procedure
  1044. //
  1045. BOOL CALLBACK MakePaletteProc(HWND hDlg, UINT Message, UINT wParam, LONG lParam)
  1046. {
  1047.     switch (Message) {
  1048.         case WM_INITDIALOG :
  1049.             SetDlgItemInt(hDlg, IDD_MakePalColors, gwPalColors, FALSE) ;
  1050.             SetDlgItemInt(hDlg, IDD_MakePalFrames, gwPalFrames, FALSE) ;
  1051.             return TRUE ;
  1052.  
  1053.         case WM_COMMAND :
  1054.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1055.                 case IDOK :
  1056.                 {
  1057.                     int         iColors ;
  1058.                     int         iFrames ;
  1059.  
  1060.                     iColors = (int) GetDlgItemInt(hDlg, IDD_MakePalColors, NULL, TRUE) ;
  1061.                     if (! (iColors > 0 && iColors <= 236 || iColors == 256)) {
  1062.                         // invalid number of palette colors
  1063.                         SetDlgItemInt(hDlg, IDD_MakePalColors, iColors, TRUE) ;
  1064.                         SetFocus(GetDlgItem(hDlg, IDD_MakePalColors)) ;
  1065.                         MessageBeep(MB_ICONEXCLAMATION) ;
  1066.                         return FALSE ;
  1067.                     }
  1068.                     iFrames = (int) GetDlgItemInt(hDlg, IDD_MakePalFrames, NULL, TRUE) ;
  1069.                     if (iFrames <= 0 || iFrames > 10000) {
  1070.                         // no frame or way t-o-o many frames !!!
  1071.                         SetDlgItemInt(hDlg, IDD_MakePalFrames, iFrames, TRUE) ;
  1072.                         SetFocus(GetDlgItem(hDlg, IDD_MakePalFrames)) ;
  1073.                         MessageBeep(MB_ICONEXCLAMATION) ;
  1074.                         return FALSE ;
  1075.                     }
  1076.                     gwPalColors = iColors ;
  1077.                     gwPalFrames = iFrames ;
  1078.  
  1079.                     EndDialog(hDlg, TRUE) ;
  1080.                     return TRUE ;
  1081.                 }
  1082.  
  1083.                 case IDCANCEL :
  1084.                     EndDialog(hDlg, FALSE) ;
  1085.                     return TRUE ;
  1086.             }
  1087.             break ;
  1088.     }
  1089.  
  1090.     return FALSE ;
  1091.  
  1092. }
  1093.  
  1094. #endif
  1095.  
  1096.  
  1097. #define CAPPAL_TIMER    902    
  1098. #define CAPTIMER_DELAY  100       // get timers as fast as possible
  1099. //
  1100. // MakePaletteProc: Palette Details Dialog Box Procedure
  1101. //
  1102. static int      siNumColors = 256;
  1103.  
  1104. BOOL CALLBACK MakePaletteProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
  1105. {
  1106.     static UINT shTimer;
  1107.     static int  siNumFrames;
  1108.     UINT        w;
  1109.     char        ach[40];
  1110.     char        achFormat[40];
  1111.     int         i, k;
  1112.  
  1113.     switch(msg) {
  1114.         case WM_INITDIALOG:
  1115.             siNumFrames = 0;
  1116.             SetDlgItemInt(hwnd, IDD_MakePalColors, siNumColors, FALSE);
  1117.             SmartWindowPosition (hwnd, ghWndCap);
  1118.             return TRUE;
  1119.             break;
  1120.  
  1121.         case WM_VSCROLL:
  1122.             /* now handle the scroll */
  1123.             i = GetDlgItemInt(hwnd, IDD_MakePalColors, NULL, FALSE);
  1124.             ArrowEditChange(GetDlgItem(hwnd, IDD_MakePalColors),
  1125.                 GET_WM_VSCROLL_CODE(wParam, lParam), 2, 256);
  1126.             k = GetDlgItemInt(hwnd, IDD_MakePalColors, NULL, FALSE);
  1127.             // Jump over the range 237 to 255
  1128.             if (k > 236 && k < 256) {
  1129.                 if (k > i) 
  1130.                    w = 256;
  1131.                 else
  1132.                    w = 236;
  1133.                 SetDlgItemInt (hwnd, IDD_MakePalColors, w, TRUE);
  1134.             }
  1135.             break;
  1136.  
  1137.         case WM_COMMAND:
  1138.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1139.                 case IDCANCEL:
  1140.                     if (siNumFrames) {
  1141.                         // The following finishes building the new palette
  1142.                         capPaletteManual (ghWndCap, FALSE, siNumColors);
  1143.                     }
  1144.  
  1145.                     if (shTimer){
  1146.                         KillTimer(hwnd, CAPPAL_TIMER);
  1147.                         shTimer = 0;
  1148.                     }
  1149.                     siNumColors = GetDlgItemInt(hwnd, IDD_MakePalColors, (BOOL FAR *)ach, FALSE);
  1150.                     siNumColors = max (2, min (256, siNumColors)); 
  1151.                     EndDialog(hwnd, siNumFrames);
  1152.                     break;
  1153.                     
  1154.                 case IDD_MakePalStart:
  1155.                     /* see if we are in START or STOP mode at   */
  1156.                     /* this time and handle each one.           */
  1157.                     SetFocus (GetDlgItem (hwnd, IDD_MakePalStart));
  1158.                     if (!siNumFrames){
  1159.                         /* this is the first frame, change the CANCEL */
  1160.                         /* button to CLOSE                              */
  1161.                         LoadString(ghInstApp, IDS_CAPPAL_CLOSE, ach, sizeof(ach));
  1162.                         SetDlgItemText(hwnd, IDCANCEL, ach);
  1163.                     }
  1164.                     if (!shTimer) {
  1165.  
  1166.                         shTimer = SetTimer(hwnd, CAPPAL_TIMER, CAPTIMER_DELAY, NULL);
  1167.  
  1168.                         if (shTimer == 0) {
  1169.                             //!!!error message here.
  1170.                             MessageBeep(0);
  1171.                             return TRUE;
  1172.                         }
  1173.  
  1174.                         /* button said START, let's set up to   */
  1175.                         /* do continuous capture.  This involves*/
  1176.                         /*   1 - disabling FRAME button         */
  1177.                         /*   2 - turning myself to STOP button  */
  1178.                         /*   3 - setting up frame timer         */
  1179.                         EnableWindow(GetDlgItem(hwnd, IDD_MakePalSingleFrame), FALSE);
  1180.                         LoadString(ghInstApp, IDS_CAPPAL_STOP, ach, sizeof(ach));
  1181.                         SetDlgItemText(hwnd, IDD_MakePalStart, ach);
  1182.                     } else {
  1183.                         /* button said STOP, turn things around */
  1184.                         /* by:                                  */
  1185.                         /*   1 - killing off timers             *
  1186.                         /*   2 - turning back into START button */
  1187.                         /*   3 - re-enabling FRAME button       */
  1188.                         // "&Start"
  1189.                         LoadString(ghInstApp, IDS_CAPPAL_START, ach, sizeof(ach));
  1190.                         SetDlgItemText(hwnd, IDD_MakePalStart, ach);
  1191.                         EnableWindow(GetDlgItem(hwnd, IDD_MakePalSingleFrame), TRUE);
  1192.                         KillTimer(hwnd, CAPPAL_TIMER);
  1193.                         shTimer = 0;
  1194.                     }
  1195.                     return TRUE;
  1196.                     break;
  1197.                     
  1198.                 case IDD_MakePalSingleFrame:
  1199.                     if (!siNumFrames){
  1200.                         /* this is the first frame, change the CANCEL */
  1201.                         /* button to CLOSE                              */
  1202.                         LoadString(ghInstApp, IDS_CAPPAL_CLOSE, ach, sizeof(ach));
  1203.                         SetDlgItemText(hwnd, IDCANCEL, ach);
  1204.                         siNumColors = GetDlgItemInt(hwnd, IDD_MakePalColors, (BOOL FAR *)ach, FALSE);
  1205.                         siNumColors = max (2, min (256, siNumColors)); 
  1206.                     }
  1207.                     // Get the palette for a single frame
  1208.                     capPaletteManual (ghWndCap, TRUE, siNumColors);
  1209.  
  1210.                     siNumFrames++;
  1211.                     LoadString(ghInstApp, IDS_CAPPAL_STATUS, achFormat, sizeof(achFormat));
  1212.                     wsprintf(ach, achFormat, siNumFrames);
  1213.                     SetDlgItemText(hwnd, IDD_MakePalNumFrames, ach);
  1214.                     return TRUE;
  1215.                     break;
  1216.  
  1217.                 case IDD_MakePalColors:
  1218.                     if (HIWORD (lParam) == EN_KILLFOCUS) {
  1219.                         w = GetDlgItemInt (hwnd, wParam, NULL, FALSE);
  1220.                         if ( w < 2) {
  1221.                             MessageBeep (0);
  1222.                             SetDlgItemInt (hwnd, wParam, 2, FALSE);
  1223.                         }
  1224.                         else if (w > 256) {
  1225.                             MessageBeep (0);
  1226.                             SetDlgItemInt (hwnd, wParam, 256, FALSE);
  1227.                         }
  1228.                     }
  1229.                     return TRUE;
  1230.                     break;
  1231.  
  1232.                 default:
  1233.                     return FALSE;
  1234.                     
  1235.             } // switch(wParam) on WM_COMMAND 
  1236.             break;
  1237.             
  1238.         case WM_TIMER:
  1239.             if (wParam == CAPPAL_TIMER){
  1240.                 SendMessage(hwnd, WM_COMMAND, IDD_MakePalSingleFrame, 0L);
  1241.             }
  1242.             break;
  1243.         default:
  1244.             return FALSE;
  1245.             
  1246.     } // switch(msg)
  1247.     return FALSE;
  1248. }
  1249.  
  1250.  
  1251.  
  1252.  
  1253. //
  1254. // CapSetUpProc: Capture SetUp Details Dialog Box Procedure
  1255. //
  1256. int FAR PASCAL CapSetUpProc(HWND hDlg, UINT Message, UINT wParam, LONG lParam)
  1257. {
  1258.     static char     achBuffer[21] ;
  1259.     UINT fValue;
  1260.  
  1261.     switch (Message) {
  1262.         case WM_INITDIALOG :
  1263.         {
  1264.  
  1265.             // Convert from MicroSecPerFrame to FPS -- that's easier !!
  1266.             MicroSecToStringRate(achBuffer, gCapParms.dwRequestMicroSecPerFrame);
  1267.             SetDlgItemText(hDlg, IDD_FrameRateData, achBuffer);
  1268.  
  1269.  
  1270.             // If time limit isn't enabled, disable the time data part
  1271.             CheckDlgButton(hDlg, IDD_TimeLimitFlag, (fValue = gCapParms.fLimitEnabled)) ;
  1272.             EnableWindow(GetDlgItem(hDlg, IDD_SecondsText), fValue) ;
  1273.             EnableWindow(GetDlgItem(hDlg, IDD_SecondsData), fValue) ;
  1274.             EnableWindow(GetDlgItem(hDlg, IDD_SecondsArrow), fValue);
  1275.  
  1276.             SetDlgItemInt(hDlg, IDD_SecondsData, gCapParms.wTimeLimit, FALSE) ;
  1277.  
  1278.  
  1279.             // disable audio buttons if no audio hardware
  1280.             {
  1281.                 CAPSTATUS cs;
  1282.  
  1283.                 capGetStatus(ghWndCap, &cs, sizeof(cs));
  1284.                 EnableWindow(GetDlgItem(hDlg, IDD_CapAudioFlag), cs.fAudioHardware);
  1285.                 EnableWindow(GetDlgItem(hDlg, IDD_AudioConfig), cs.fAudioHardware);
  1286.  
  1287.                 CheckDlgButton(hDlg, IDD_CapAudioFlag, gCapParms.fCaptureAudio);
  1288.             }
  1289.  
  1290.  
  1291.  
  1292.             /*
  1293.              * Capture To Memory means allocate as many memory buffers
  1294.              *  as possible.
  1295.              * Capture To Disk means only allocate enough buffers
  1296.              *  to get us through disk seeks and thermal recalibrations.
  1297.              */
  1298.  
  1299.             // The use of fUsingDOSMemory is now just a means of keeping
  1300.             // track of whether using lots of buffers.  We never actually
  1301.             // allocate exclusively from memory under 1Meg.
  1302.  
  1303.             CheckRadioButton(hDlg, IDD_CaptureToDisk, IDD_CaptureToMemory,
  1304.               (gCapParms.fUsingDOSMemory)? IDD_CaptureToDisk : IDD_CaptureToMemory);
  1305.  
  1306.             // Find out how many MCI devices can source video
  1307.             if (CountMCIDevices(MCI_DEVTYPE_VCR) +
  1308.                 CountMCIDevices(MCI_DEVTYPE_VIDEODISC) == 0) {
  1309.                 // if no VCRs or Videodiscs, disable the controls
  1310.                 EnableWindow(GetDlgItem(hDlg, IDD_MCIControlFlag), FALSE);
  1311.                 EnableWindow(GetDlgItem(hDlg, IDD_MCISetup), FALSE);
  1312.             } else {
  1313.                 EnableWindow(GetDlgItem(hDlg, IDD_MCIControlFlag), TRUE);
  1314.  
  1315.                 // if MCI Control is selected, enable the setup button
  1316.                 CheckDlgButton(hDlg, IDD_MCIControlFlag,
  1317.                     gCapParms.fMCIControl);
  1318.                 EnableWindow(GetDlgItem(hDlg, IDD_MCISetup), gCapParms.fMCIControl);
  1319.             }
  1320.  
  1321.             // place the dialog to avoid covering the capture window
  1322.             SmartWindowPosition(hDlg, ghWndCap);
  1323.             return TRUE ;
  1324.         }
  1325.  
  1326.         case WM_COMMAND :
  1327.             switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1328.                 case IDD_TimeLimitFlag :
  1329.                     // If this flag changes, en/dis-able time limit data part
  1330.                     fValue = IsDlgButtonChecked(hDlg, IDD_TimeLimitFlag) ;
  1331.                     EnableWindow(GetDlgItem(hDlg, IDD_SecondsText), fValue) ;
  1332.                     EnableWindow(GetDlgItem(hDlg, IDD_SecondsData), fValue) ;
  1333.                     EnableWindow(GetDlgItem(hDlg, IDD_SecondsArrow), fValue);
  1334.                     return TRUE ;
  1335.  
  1336.                 case IDD_MCIControlFlag :
  1337.                     // If this flag changes, en/dis-able MCI Setup button
  1338.                     fValue = IsDlgButtonChecked(hDlg, IDD_MCIControlFlag) ;
  1339.                     EnableWindow(GetDlgItem(hDlg, IDD_MCISetup), fValue) ;
  1340.                     return TRUE ;
  1341.  
  1342.                 case IDD_CapAudioFlag:
  1343.                     fValue = IsDlgButtonChecked(hDlg, IDD_CapAudioFlag) ;
  1344.                     EnableWindow(GetDlgItem(hDlg, IDD_AudioConfig), fValue) ;
  1345.                     return TRUE ;
  1346.  
  1347.  
  1348.                 case IDD_FrameRateData:
  1349.                     // get the requested frame rate and check it against bounds
  1350.                     if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_KILLFOCUS) {
  1351.                         long l, new_l;
  1352.  
  1353.                         GetDlgItemText(hDlg, IDD_FrameRateData, achBuffer, sizeof(achBuffer));
  1354.                         new_l = l = StringRateToMicroSec(achBuffer);
  1355.  
  1356.                         // note that the MAX rate is SMALL! hence <max, >min
  1357.                         if (l == 0) {
  1358.                             new_l = DEF_CAPTURE_RATE;
  1359.                         } else if (l < MAX_CAPTURE_RATE) {
  1360.                             new_l = MAX_CAPTURE_RATE;
  1361.                         } else if (l > MIN_CAPTURE_RATE) {
  1362.                             new_l = MIN_CAPTURE_RATE;
  1363.                         }
  1364.                         if (l != new_l) {
  1365.                             MicroSecToStringRate(achBuffer, new_l);
  1366.                             SetDlgItemText(hDlg, IDD_FrameRateData, achBuffer);
  1367.                         }
  1368.                     }
  1369.                     break;
  1370.  
  1371.                 case IDD_SecondsData:
  1372.                 {
  1373.                     long l, new_l;
  1374.  
  1375.                     // get requested time limit and check validity
  1376.                     GetDlgItemText(hDlg, IDD_SecondsData, achBuffer, sizeof(achBuffer));
  1377.                     new_l = l = atol(achBuffer);
  1378.                     if (l < 1) {
  1379.                         new_l = 1;
  1380.                     } else if (l > 9999) {
  1381.                         new_l = 9999;
  1382.                     } else {
  1383.                         // make sure there are no non-digit chars
  1384.                         // atol() will ignore trailing non-digit characters
  1385.                         int c = 0;
  1386.                         while (achBuffer[c]) {
  1387.                             if (IsCharAlpha(achBuffer[c]) ||
  1388.                                 !IsCharAlphaNumeric(achBuffer[c])) {
  1389.  
  1390.                                 // string contains non-digit chars - reset
  1391.                                 new_l = 1;
  1392.                                 break;
  1393.                             }
  1394.                             c++;
  1395.                         }
  1396.                     }
  1397.                     if (new_l != l) {
  1398.                         wsprintf(achBuffer, "%ld", new_l);
  1399.                         SetDlgItemText(hDlg, IDD_SecondsData, achBuffer);
  1400.                     }
  1401.                     break;
  1402.                 }
  1403.  
  1404.                 // show audio format setup dialog
  1405.                 case IDD_AudioConfig:
  1406.  
  1407.                     // rather than duplicate lots of code from the
  1408.                     // main vidcap winproc, lets just ask it to show the dlg...
  1409.                     SendMessage(ghWndMain, WM_COMMAND,
  1410.                             GET_WM_COMMAND_MPS(IDM_O_AUDIOFORMAT, NULL, 0));
  1411.  
  1412.                     break;
  1413.  
  1414.  
  1415.                 // show MCI step control dialog
  1416.                 case IDD_MCISetup:
  1417.                     DoDialog(hDlg, IDD_MCISETUP, MCISetupProc, 0);
  1418.                     break;
  1419.  
  1420.                 // show video format setup dialog
  1421.                 case IDD_VideoConfig:
  1422.                     // rather than duplicate lots of code from the
  1423.                     // main vidcap winproc, lets just ask it to show the dlg...
  1424.                     SendMessage(ghWndMain, WM_COMMAND,
  1425.                             GET_WM_COMMAND_MPS(IDM_O_VIDEOFORMAT, NULL, 0));
  1426.                     break;
  1427.  
  1428.                 // show the compressor selector dialog
  1429.                 case IDD_CompConfig:
  1430.                     capDlgVideoCompression(ghWndCap);
  1431.                     break;
  1432.  
  1433.  
  1434.  
  1435.                 case IDOK :
  1436.                 {
  1437.  
  1438.                     gCapParms.fCaptureAudio =
  1439.                                 IsDlgButtonChecked(hDlg, IDD_CapAudioFlag) ;
  1440.                     gCapParms.fMCIControl =
  1441.                             IsDlgButtonChecked(hDlg, IDD_MCIControlFlag);
  1442.                     gCapParms.fLimitEnabled = IsDlgButtonChecked(hDlg, IDD_TimeLimitFlag) ;
  1443.  
  1444.                     GetDlgItemText(hDlg, IDD_FrameRateData, achBuffer, sizeof(achBuffer));
  1445.                     gCapParms.dwRequestMicroSecPerFrame = StringRateToMicroSec(achBuffer);
  1446.                     if (gCapParms.dwRequestMicroSecPerFrame == 0) {
  1447.                         gCapParms.dwRequestMicroSecPerFrame = DEF_CAPTURE_RATE;
  1448.                     }
  1449.  
  1450.                     GetDlgItemText(hDlg, IDD_SecondsData, achBuffer, sizeof(achBuffer));
  1451.                     if (gCapParms.fLimitEnabled) {
  1452.                          gCapParms.wTimeLimit  = (UINT) atol(achBuffer);
  1453.                     }
  1454.  
  1455.                     // fUsingDOSMemory is archaic and is now just a flag reflecting
  1456.                     // the "CaptureToDisk" selection.
  1457.                     // 
  1458.                     gCapParms.fUsingDOSMemory = 
  1459.                                 IsDlgButtonChecked(hDlg, IDD_CaptureToDisk);
  1460.  
  1461.                     EndDialog(hDlg, TRUE) ;
  1462.                     return TRUE ;
  1463.                 }
  1464.  
  1465.                 case IDCANCEL :
  1466.                     EndDialog(hDlg, FALSE) ;
  1467.                     return TRUE ;
  1468.             }
  1469.             break ;
  1470.  
  1471.         case WM_VSCROLL:
  1472.         // message from one of the arrow spinbuttons
  1473.         {
  1474.             UINT id;
  1475.  
  1476.             id = GetDlgCtrlID(GET_WM_COMMAND_HWND(wParam, lParam));
  1477.             if (id == IDD_FrameRateArrow) {
  1478.                 // format n.nnn
  1479.                 MilliSecVarArrowEditChange(
  1480.                     GetDlgItem(hDlg, IDD_FrameRateData),
  1481.                     GET_WM_VSCROLL_CODE(wParam, lParam),
  1482.                     1, 100, 1);
  1483.             } else {
  1484.                 // simple integer format
  1485.                 ArrowEditChange(
  1486.                     GetDlgItem(hDlg, IDD_SecondsData),
  1487.                     GET_WM_VSCROLL_CODE(wParam, lParam),
  1488.                     1, 30000);
  1489.             }
  1490.             break;
  1491.         }
  1492.  
  1493.     }
  1494.  
  1495.     return FALSE ;
  1496. }
  1497.  
  1498. /*
  1499.  * preferences dialog - sets global options about background colour,
  1500.  * presence of toolbar, status bar etc
  1501.  */
  1502. int FAR PASCAL
  1503. PrefsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1504. {
  1505.     DWORD indexsz;
  1506.  
  1507.     switch(message) {
  1508.  
  1509.  
  1510.     case WM_INITDIALOG:
  1511.         CheckDlgButton(hDlg, IDD_PrefsStatus, gbStatusBar);
  1512.         CheckDlgButton(hDlg, IDD_PrefsToolbar, gbToolBar);
  1513.         CheckDlgButton(hDlg, IDD_PrefsCentre, gbCentre);
  1514.         CheckDlgButton(hDlg, IDD_PrefsSizeFrame, gbAutoSizeFrame);
  1515.         CheckRadioButton(hDlg, IDD_PrefsDefBackground, IDD_PrefsBlack, gBackColour);
  1516.  
  1517.         CheckRadioButton(hDlg, IDD_PrefsSmallIndex, IDD_PrefsBigIndex,
  1518.                     (gCapParms.dwIndexSize == CAP_LARGE_INDEX) ?
  1519.                     IDD_PrefsBigIndex : IDD_PrefsSmallIndex);
  1520.  
  1521.         CheckRadioButton(hDlg, IDD_PrefsMasterAudio, IDD_PrefsMasterNone,
  1522.                     gCapParms.AVStreamMaster + IDD_PrefsMasterAudio);
  1523.  
  1524.         return(TRUE);
  1525.  
  1526.     case WM_COMMAND:
  1527.         switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  1528.         case IDCANCEL:
  1529.             EndDialog(hDlg, FALSE);
  1530.             return(TRUE);
  1531.  
  1532.         case IDOK:
  1533.             gbStatusBar = IsDlgButtonChecked(hDlg, IDD_PrefsStatus);
  1534.             gbToolBar = IsDlgButtonChecked(hDlg, IDD_PrefsToolbar);
  1535.             gbCentre = IsDlgButtonChecked(hDlg, IDD_PrefsCentre);
  1536.             gbAutoSizeFrame = IsDlgButtonChecked(hDlg, IDD_PrefsSizeFrame);
  1537.  
  1538.             if (IsDlgButtonChecked(hDlg, IDD_PrefsDefBackground)) {
  1539.                 gBackColour = IDD_PrefsDefBackground;
  1540.             } else if (IsDlgButtonChecked(hDlg, IDD_PrefsLtGrey)) {
  1541.                 gBackColour = IDD_PrefsLtGrey;
  1542.             } else if (IsDlgButtonChecked(hDlg, IDD_PrefsDkGrey)) {
  1543.                 gBackColour = IDD_PrefsDkGrey;
  1544.             } else {
  1545.                 gBackColour = IDD_PrefsBlack;
  1546.             }
  1547.  
  1548.             if (IsDlgButtonChecked(hDlg, IDD_PrefsSmallIndex)) {
  1549.                 indexsz = CAP_SMALL_INDEX;
  1550.  
  1551.             } else {
  1552.                 indexsz = CAP_LARGE_INDEX;
  1553.             }
  1554.             if (indexsz != gCapParms.dwIndexSize) {
  1555.                 gCapParms.dwIndexSize = indexsz;
  1556.             }
  1557.  
  1558.             if (IsDlgButtonChecked(hDlg, IDD_PrefsMasterAudio)) {
  1559.                 gCapParms.AVStreamMaster = AVSTREAMMASTER_AUDIO;
  1560.             }
  1561.             else {
  1562.                 gCapParms.AVStreamMaster = AVSTREAMMASTER_NONE;
  1563.             }
  1564.  
  1565.             EndDialog(hDlg, TRUE);
  1566.             return(TRUE);
  1567.         }
  1568.         break;
  1569.     }
  1570.     return FALSE;
  1571. }
  1572.  
  1573.  
  1574. int FAR PASCAL
  1575. NoHardwareDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1576. {
  1577.     static HBRUSH hbr;
  1578.  
  1579.     switch(message) {
  1580.     case WM_INITDIALOG:
  1581.         // lParam contains the argument to DialogBoxParam which is the
  1582.         // reason text
  1583.         SetDlgItemText(hDlg, IDD_FailReason, (LPSTR) lParam);
  1584.  
  1585.         hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  1586.         return TRUE;
  1587.  
  1588.     case WM_DESTROY:
  1589.         DeleteObject(hbr);
  1590.  
  1591. #ifdef _WIN32
  1592.     case WM_CTLCOLORSTATIC:
  1593. #else
  1594.     case WM_CTLCOLOR:
  1595. #endif
  1596.         if (GET_WM_CTLCOLOR_HWND(wParam, lParam, message) == GetDlgItem(hDlg, IDD_FailReason)) {
  1597.  
  1598.             HDC hdc;
  1599.  
  1600.             hdc = GET_WM_CTLCOLOR_HDC(wParam, lParam, message);
  1601.  
  1602.             SetTextColor(hdc, RGB(0xff, 0, 0));
  1603.             SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  1604.  
  1605.             // in order to ensure that the text colour we have chosen for
  1606.             // this control is used, we need to actually return a brush.
  1607.             // for win31, we also need to align the brush
  1608. #ifndef _WIN32
  1609.             {
  1610.                 POINT pt;
  1611.  
  1612.                 pt.x = 0;
  1613.                 pt.y = 0;
  1614.                 ClientToScreen(hDlg, &pt);
  1615.                 UnrealizeObject(hbr);
  1616.                 SetBrushOrg(hdc, pt.x, pt.y);
  1617.             }
  1618. #endif
  1619.  
  1620.             return((int) hbr);
  1621.  
  1622.         }
  1623.         break;
  1624.  
  1625.     case WM_COMMAND:
  1626.         switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  1627.         case IDOK:
  1628.             EndDialog(hDlg, TRUE);
  1629.             return(TRUE);
  1630.         case IDCANCEL:
  1631.             EndDialog(hDlg, FALSE);
  1632.             return(TRUE);
  1633.         }
  1634.         break;
  1635.     }
  1636.  
  1637.     return(FALSE);
  1638. }
  1639.  
  1640.  
  1641. //capture selected single frames
  1642. long
  1643. FAR PASCAL
  1644. CapFramesProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
  1645. {
  1646.     char ach[MAX_PATH*2];
  1647.     char achName[MAX_PATH];
  1648.  
  1649.     static BOOL bFirst;
  1650.     static int iFrames;
  1651.  
  1652.     switch(Message) {
  1653.     case WM_INITDIALOG:
  1654.  
  1655.         // write out the prompt message including the capture file name
  1656.         capFileGetCaptureFile(ghWndCap, achName, sizeof(achName));
  1657.         wsprintf(ach, tmpString(IDS_PROMPT_CAPFRAMES), achName);
  1658.         SetDlgItemText(hDlg, IDD_CapMessage, ach);
  1659.  
  1660.         bFirst = TRUE;
  1661.  
  1662.         //move dialog so it doesn't obscure the capture window
  1663.         SmartWindowPosition(hDlg, ghWndCap);
  1664.  
  1665.         return(TRUE);
  1666.  
  1667.     case WM_COMMAND:
  1668.         switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  1669.  
  1670.         case IDCANCEL:
  1671.             if (!bFirst) {
  1672.                 capCaptureSingleFrameClose(ghWndCap);
  1673.                 EndDialog(hDlg, TRUE);
  1674.             } else {
  1675.                 EndDialog(hDlg, FALSE);
  1676.             }
  1677.             return(TRUE);
  1678.  
  1679.         case IDOK:
  1680.             if (bFirst) {
  1681.                 bFirst = FALSE;
  1682.                 iFrames = 0;
  1683.                 capCaptureSingleFrameOpen(ghWndCap);
  1684.  
  1685.                 SetDlgItemText(hDlg, IDCANCEL, tmpString(IDS_CAP_CLOSE));
  1686.  
  1687.             }
  1688.             capCaptureSingleFrame(ghWndCap);
  1689.             iFrames++;
  1690.  
  1691.             wsprintf(ach, tmpString(IDS_STATUS_NUMFRAMES), iFrames);
  1692.             SetDlgItemText(hDlg, IDD_CapNumFrames, ach);
  1693.             return(TRUE);
  1694.  
  1695.         }
  1696.         break;
  1697.     }
  1698.     return(FALSE);
  1699. }
  1700.  
  1701. // enumerate all the MCI devices of a particular type and add them and
  1702. // their descriptions to a combo box list.
  1703. //
  1704. void
  1705. AddMCIDeviceNames(WORD wDeviceType, HWND hwndCB)
  1706. {
  1707.     int   nIndex;
  1708.     MCI_OPEN_PARMS mciOp;
  1709.     MCI_INFO_PARMS mciIp;
  1710.     MCI_SYSINFO_PARMS mciSIP;
  1711.     MCI_GENERIC_PARMS mciGp;
  1712.     char buf[MAXPNAMELEN + 128]; // Contains eg. Name\t\tVideodisc1
  1713.     char buf2 [64];
  1714.     int maxdevs;
  1715.     DWORD dwRet;
  1716.  
  1717.     // To get the user readable names of the devices, we
  1718.     // must open all appropriate devices, and then get info.
  1719.  
  1720.     // MCI Open structure
  1721.     mciOp.dwCallback = 0;
  1722.     mciOp.lpstrElementName = NULL;
  1723.     mciOp.lpstrAlias = NULL;
  1724.  
  1725.     // MCI Info structure
  1726.     mciIp.dwCallback = 0;
  1727.     mciIp.lpstrReturn = (LPSTR) buf;
  1728.     mciIp.dwRetSize = MAXPNAMELEN - 1;
  1729.  
  1730.     // MCI SysInfo structure
  1731.     mciSIP.dwCallback = 0;
  1732.     mciSIP.lpstrReturn = (LPSTR) buf2;
  1733.     mciSIP.dwRetSize = sizeof (buf2);
  1734.     mciSIP.wDeviceType = wDeviceType;
  1735.  
  1736.     // MCI Generic structure
  1737.     mciGp.dwCallback = 0;
  1738.  
  1739.     // Load the combobox with the product info name, followed by
  1740.     // a comma, then a space, and then the mci device name. This allows a
  1741.     // single alphabetized list to be kept.
  1742.  
  1743.     // eg.
  1744.     // Pioneer Laserdisc, videodisc1
  1745.  
  1746.     maxdevs = CountMCIDevices((WORD)mciSIP.wDeviceType);
  1747.     for (nIndex = 0; nIndex < maxdevs; nIndex++) {
  1748.  
  1749.        // Get the system name eg. Videodisc1
  1750.        mciSIP.dwNumber = nIndex + 1;
  1751.        dwRet = mciSendCommand (0, MCI_SYSINFO,
  1752.                     MCI_SYSINFO_NAME,
  1753.                     (DWORD) (LPVOID) &mciSIP);
  1754.  
  1755.        mciOp.lpstrDeviceType =
  1756.             (LPSTR) MAKELONG (wDeviceType, nIndex);
  1757.  
  1758.        if (!(dwRet = mciSendCommand(0, MCI_OPEN,
  1759.                     MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
  1760.                     MCI_OPEN_SHAREABLE,
  1761.                     (DWORD) (LPVOID) &mciOp))) {
  1762.             if (!(dwRet = mciSendCommand (mciOp.wDeviceID, MCI_INFO,
  1763.                             MCI_WAIT | MCI_INFO_PRODUCT,
  1764.                             (DWORD) (LPVOID) &mciIp))) {
  1765.                 lstrcat (buf, ", ");         // append the delimiter
  1766.                 lstrcat (buf, buf2);         // append the system name
  1767.                 // Whew, finally put it in the listbox
  1768.                 SendMessage( hwndCB, CB_ADDSTRING, 0,
  1769.                                 (LONG)(LPSTR) buf);
  1770.             } //endif got INFO
  1771.             // Close it now
  1772.             mciSendCommand (mciOp.wDeviceID, MCI_CLOSE,
  1773.                             MCI_WAIT,
  1774.                             (DWORD) (LPVOID) &mciGp);
  1775.        } // endif OPEN
  1776.     } // endif for all devices of this type
  1777. }
  1778.  
  1779.  
  1780. //
  1781. // dialog proc to select MCI device and parameters, including start,
  1782. // stop times.
  1783. BOOL FAR PASCAL
  1784. MCISetupProc(HWND hwnd, unsigned msg, UINT wParam, LONG lParam)
  1785. {
  1786.   HWND  hwndCB;
  1787.   DWORD dw;
  1788.   char buf[MAXPNAMELEN];
  1789.   BOOL f;
  1790.   int j;
  1791.   static int nLastCBIndex = 0;
  1792.   static DWORD tdwMCIStartTime;
  1793.   static DWORD tdwMCIStopTime;
  1794.  
  1795.  
  1796.  
  1797.   switch (msg) {
  1798.     case WM_INITDIALOG:
  1799.  
  1800.           CheckRadioButton(hwnd, IDD_MCI_PLAY, IDD_MCI_STEP,
  1801.                 gCapParms.fStepMCIDevice ?
  1802.                             IDD_MCI_STEP : IDD_MCI_PLAY );
  1803.  
  1804.         // enable averaging options only in step mode
  1805.         EnableWindow (GetDlgItem (hwnd, IDD_MCI_AVERAGE_2X), gCapParms.fStepMCIDevice);
  1806.         EnableWindow (GetDlgItem (hwnd, IDD_MCI_AVERAGE_FR), gCapParms.fStepMCIDevice);
  1807.     SetDlgItemInt(hwnd, IDD_MCI_AVERAGE_FR, gCapParms.wStepCaptureAverageFrames, FALSE);
  1808.         CheckDlgButton (hwnd, IDD_MCI_AVERAGE_2X, gCapParms.fStepCaptureAt2x);
  1809.  
  1810.         // save current dialog time settings
  1811.         tdwMCIStartTime = gCapParms.dwMCIStartTime;
  1812.         tdwMCIStopTime  = gCapParms.dwMCIStopTime;
  1813.  
  1814.         TimeMSToHMSString (gCapParms.dwMCIStartTime, buf);
  1815.         SetDlgItemText (hwnd, IDD_MCI_STARTTIME, buf);
  1816.         TimeMSToHMSString (gCapParms.dwMCIStopTime, buf);
  1817.         SetDlgItemText (hwnd, IDD_MCI_STOPTIME, buf);
  1818.  
  1819.  
  1820.         // fill combo box with list of MCI devices
  1821.     hwndCB = GetDlgItem( hwnd, IDD_MCI_SOURCE );
  1822.         AddMCIDeviceNames(MCI_DEVTYPE_VIDEODISC, hwndCB);
  1823.         AddMCIDeviceNames(MCI_DEVTYPE_VCR, hwndCB);
  1824.  
  1825.  
  1826.         // set the selection to whatever he chose last time through this dlg
  1827.         // default is the first entry.
  1828.            SendMessage( hwndCB, CB_SETCURSEL, nLastCBIndex, 0L);
  1829.     break;
  1830.  
  1831.     case WM_COMMAND:
  1832.     switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1833.         case IDOK:
  1834.                 // i think the point of this is to ensure that
  1835.                 // the KILLFOCUS processing for the edit boxes has been done
  1836.                 // and thus the temp times are the same as the dialog text
  1837.                 SetFocus(GET_WM_COMMAND_HWND(wParam, lParam));
  1838.  
  1839.  
  1840.                 MCIGetDeviceNameAndIndex (hwnd, &nLastCBIndex, gachMCIDeviceName);
  1841.                 capSetMCIDeviceName(ghWndCap, gachMCIDeviceName) ;
  1842.                 gCapParms.fStepMCIDevice = IsDlgButtonChecked (hwnd, IDD_MCI_STEP);
  1843.  
  1844.                 // pick up the temp times - these were set on KILLFOCUS msgs
  1845.                 // (when we did validation and string->dword conversion
  1846.                 gCapParms.dwMCIStartTime = tdwMCIStartTime;
  1847.                 gCapParms.dwMCIStopTime  = tdwMCIStopTime;
  1848.  
  1849.                 gCapParms.fStepCaptureAt2x = IsDlgButtonChecked (hwnd, IDD_MCI_AVERAGE_2X);
  1850.                 gCapParms.wStepCaptureAverageFrames = GetDlgItemInt (hwnd, IDD_MCI_AVERAGE_FR, NULL, FALSE);
  1851.  
  1852.         EndDialog(hwnd, TRUE);
  1853.         break;
  1854.         
  1855.         case IDCANCEL:
  1856.         EndDialog(hwnd, 0);
  1857.         break;
  1858.  
  1859.             case IDD_MCI_STEP:
  1860.             case IDD_MCI_PLAY:
  1861.                 //averaging only enabled in play mode
  1862.                 f = IsDlgButtonChecked (hwnd, IDD_MCI_STEP);
  1863.                 EnableWindow (GetDlgItem (hwnd, IDD_MCI_AVERAGE_2X), f);
  1864.                 EnableWindow (GetDlgItem (hwnd, IDD_MCI_AVERAGE_FR), f);
  1865.                 break;
  1866.  
  1867.             case IDD_MCI_AVERAGE_FR:
  1868.                 // validate the count of frames to average 1..100
  1869.                 if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_KILLFOCUS) {
  1870.                     j = GetDlgItemInt(hwnd,
  1871.                             GET_WM_COMMAND_ID(wParam, lParam), NULL, FALSE);
  1872.                     // Limit frames to average between 1 and 100
  1873.                     if (j < 1 || j > 100) {
  1874.                     SetDlgItemInt (hwnd,
  1875.                             GET_WM_COMMAND_ID(wParam, lParam), 1, FALSE);
  1876.                     }
  1877.                 }
  1878.                 break;
  1879.  
  1880.             case IDD_MCI_STARTSET:
  1881.         case IDD_MCI_STOPSET:
  1882.                 // set the start or stop time to be the time
  1883.                 // on the device right now.
  1884.  
  1885.                 // MCI devices could yield and cause us to re-enter - the
  1886.                 // simplest answer seems to be to disable the dialog
  1887.                 EnableWindow(hwnd, FALSE);
  1888.  
  1889.                 MCIGetDeviceNameAndIndex (hwnd, &nLastCBIndex, buf);
  1890.  
  1891.                 if (MCIDeviceOpen (buf)) {
  1892.                     if (GET_WM_COMMAND_ID(wParam, lParam) == IDD_MCI_STARTSET) {
  1893.                         if (MCIDeviceGetPosition (&tdwMCIStartTime)) {
  1894.                            TimeMSToHMSString (tdwMCIStartTime, buf);
  1895.                            SetDlgItemText (hwnd, IDD_MCI_STARTTIME, buf);
  1896.                         }
  1897.                         else {
  1898.                             MessageBoxID(IDS_MCI_CONTROL_ERROR,
  1899.                                         MB_OK|MB_ICONEXCLAMATION);
  1900.                         }
  1901.                     }
  1902.                     else {
  1903.                         if (MCIDeviceGetPosition (&tdwMCIStopTime)) {
  1904.                             TimeMSToHMSString (tdwMCIStopTime, buf);
  1905.                             SetDlgItemText (hwnd, IDD_MCI_STOPTIME, buf);
  1906.                         }
  1907.                         else {
  1908.                             MessageBoxID(IDS_MCI_CONTROL_ERROR,
  1909.                                         MB_OK|MB_ICONEXCLAMATION);
  1910.                         }
  1911.                     }
  1912.                     MCIDeviceClose ();
  1913.  
  1914.                 } else {
  1915.                     // cant open device
  1916.                     MessageBoxID(IDS_MCI_CONTROL_ERROR,
  1917.                                 MB_OK|MB_ICONEXCLAMATION);
  1918.                 }
  1919.                 EnableWindow(hwnd, TRUE);
  1920.                 break;
  1921.  
  1922.  
  1923.             case IDD_MCI_STARTTIME:
  1924.             case IDD_MCI_STOPTIME:
  1925.                 if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_KILLFOCUS) {
  1926.                     GetDlgItemText (hwnd,
  1927.                         GET_WM_COMMAND_ID(wParam, lParam), buf, sizeof (buf));
  1928.                     if ((dw = TimeHMSStringToMS (buf)) == -1) {
  1929.                         // Error in string, reset
  1930.                         MessageBeep (0);
  1931.                         if (GET_WM_COMMAND_ID(wParam, lParam) == IDD_MCI_STARTTIME)
  1932.                             dw = tdwMCIStartTime;
  1933.                         else
  1934.                             dw = tdwMCIStopTime;
  1935.                     }
  1936.                     if (GET_WM_COMMAND_ID(wParam, lParam) == IDD_MCI_STARTTIME) {
  1937.                         tdwMCIStartTime = dw;
  1938.                         TimeMSToHMSString (tdwMCIStartTime, buf);
  1939.                         SetDlgItemText (hwnd, IDD_MCI_STARTTIME, buf);
  1940.                     }
  1941.                     else {
  1942.                         tdwMCIStopTime = dw;
  1943.                         TimeMSToHMSString (tdwMCIStopTime, buf);
  1944.                         SetDlgItemText (hwnd, IDD_MCI_STOPTIME, buf);
  1945.                     }
  1946.                 }
  1947.                 break;
  1948.     }
  1949.     break;
  1950.  
  1951.   }
  1952.   return FALSE;
  1953. }
  1954.  
  1955.