home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / DSSHOW3D / MAINWND.CPP < prev    next >
C/C++ Source or Header  |  1996-08-28  |  17KB  |  656 lines

  1. #include <windows.h>
  2. #include <windowsx.h>
  3. #include <commctrl.h>
  4. #include <commdlg.h>
  5.  
  6. #include "resource.h"
  7. #include "DSShow3D.h"
  8. #include "GVars.h"
  9.  
  10. #include "MainWnd.h"
  11. #include "FInfo3D.h"
  12. #include "FileInfo.h"
  13. #include "LsnrInfo.h"
  14. #include "wave.h"
  15. #include "debug.h"
  16.  
  17. static HWND hMainWndClient;
  18.  
  19. MainWnd::MainWnd()
  20. {
  21.     m_fCreated = FALSE;
  22.     m_hwnd = NULL;
  23.     m_n3DBuffers = 0;
  24.     ZeroMemory( &m_dscaps, sizeof(DSCAPS));
  25.     m_dscaps.dwSize = sizeof(m_dscaps);
  26. }
  27.  
  28.  
  29. MainWnd::~MainWnd()
  30. {
  31.     // This situation should never really occur, but we should make sure
  32.     // that there are no coding errors by asserting that fact.
  33.     if( m_hwnd )
  34.     {
  35.     ASSERT_HWND(m_hwnd);
  36.     ::DestroyWindow( m_hwnd );
  37.     m_hwnd = NULL;
  38.     m_fCreated = FALSE;
  39.     }
  40. }
  41.  
  42.  
  43. BOOL MainWnd::Create()
  44. {
  45.     if( m_fCreated )
  46.     return FALSE;
  47.  
  48.     ASSERT( NULL == m_hwnd );
  49.     m_hwnd = CreateWindowEx( WS_EX_ACCEPTFILES,
  50.                 gszAppWndClass,
  51.                 gszAppCaption,
  52.                 WS_OVERLAPPEDWINDOW,
  53.                 CW_USEDEFAULT,
  54.                 CW_USEDEFAULT,
  55.                 200,
  56.                 150,
  57.                 (HWND)NULL,
  58.                 (HMENU)NULL,
  59.                 (HANDLE)ghInst,
  60.                 (LPSTR)NULL );
  61.  
  62.     if( !m_hwnd )
  63.     return FALSE;
  64.  
  65.     SetWindowLong( m_hwnd, GWL_USERDATA, (LONG)this );
  66.     m_fCreated = TRUE;
  67.  
  68.     EnableMenuItem(GetMenu(m_hwnd), 2, MF_BYPOSITION |
  69.            (m_dlInfoList.GetElementCount() ? MF_ENABLED : MF_GRAYED));
  70.     DrawMenuBar( m_hwnd );
  71.  
  72.     UpdateStatus();
  73.  
  74.     return TRUE;
  75. }
  76.  
  77.  
  78. int MainWnd::MessageBox( LPCSTR lpcszMessage, UINT uType )
  79. {
  80.     return ::MessageBox( m_hwnd, lpcszMessage, gszAppName, uType );
  81. }
  82.  
  83. int MainWnd::MessageBox( UINT uResID, UINT uType )
  84. {
  85.     // TODO Make the 512 some defined constant
  86.     LPTSTR  lptszMessage = new TCHAR[512];
  87.     int     nRet;
  88.  
  89.     if( !lptszMessage )
  90.     return 0;
  91.  
  92.     LoadString( ghInst, uResID, lptszMessage, 512 );
  93.     nRet = ::MessageBox( m_hwnd, lptszMessage, gszAppName, uType );
  94.     delete[] lptszMessage;
  95.  
  96.     return nRet;
  97. }
  98.  
  99. BOOL MainWnd::OnTimer( WPARAM wParam, LPARAM lParam )
  100. {
  101.     // Move to the Head of the list
  102.     m_dlInfoList.SetAtHead();
  103.     
  104.     if( NULL != gpListenerInfo )
  105.     gpListenerInfo->UpdateUI();
  106.  
  107.     // While the current element isn't NULL, call OnTimer on each FileInfo
  108.     for( int i = 0; i < m_dlInfoList.GetElementCount(); i++ )
  109.     {
  110.     m_dlInfoList.GetCurrent()->UpdateUI();
  111.     // Overloaded increment moves to next position in the list
  112.     m_dlInfoList++;
  113.     }
  114.     return TRUE;
  115. }
  116.  
  117. void MainWnd::OnDestroy()
  118. {
  119.     HRESULT     hr = 0;
  120.  
  121.     if( gdwTimer != 0 )
  122.     {
  123.     KillTimer( m_hwnd, gdwTimer );
  124.     gdwTimer = 0;
  125.     }
  126.  
  127.     if( NULL != gpwfxFormat )
  128.     {
  129.     delete gpwfxFormat;
  130.     gpwfxFormat = NULL;
  131.     }
  132.  
  133.     /* Destroy the direct sound object. */
  134.     if( gp3DListener != NULL )
  135.     {
  136.     DPF( 3, "Releasing 3D Listener in MainWnd::OnDestroy()" );
  137.     gp3DListener->Release();
  138.     gp3DListener = NULL;
  139.     }
  140.     if( gpdsbPrimary )
  141.     {
  142.     DPF( 3, "Releasing Primary in MainWnd::OnDestroy()" );
  143.     gpdsbPrimary->Stop();
  144.     gpdsbPrimary->Release();
  145.     gpdsbPrimary = NULL;
  146.     }
  147.     if( gpds != NULL )
  148.     {
  149.     DPF( 3, "Releasing DSound object in MainWnd::OnDestroy()" );
  150.     gpds->Release();
  151.     gpds = NULL;
  152.     }
  153.  
  154.     if( gfCOMInitialized )
  155.     CoUninitialize();
  156.  
  157. //    WriteProfileString( gszAppName, "EnumDrivers", gfEnumDrivers ? "1" : "0" );
  158.  
  159.     if( m_hwnd )
  160.     m_hwnd = NULL;
  161.     return;
  162. }
  163.  
  164.  
  165. /* MainWndProc()
  166.  *
  167.  *    Window message handler function for the main application window.
  168.  * For the most part, this sucker just dispatchs calls to some helper
  169.  * functions in this module which do the actual handling.
  170.  */
  171. LRESULT CALLBACK MainWndProc( HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam )
  172. {
  173.     if( !hWnd )
  174.     return 0L;
  175.  
  176.     // This will be a valid pointer to the class object for any message
  177.     // after the WM_CREATE
  178.     MainWnd *pmw = (MainWnd *)GetWindowLong( hWnd, GWL_USERDATA );
  179.     
  180.     switch (message)
  181.     {
  182.     case WM_CREATE:
  183.         // If we want to do anything with the class here, we'll have
  184.         // to modify the code to pass pmw in LPARAM since there's no
  185.         // other way to get it yet: the code that sets the WindowLong
  186.         // user data has not yet executed
  187.         break;
  188.  
  189.     case WM_ACTIVATE:
  190.         ASSERT( NULL != pmw );
  191.         pmw->UpdateStatus();
  192.         break;
  193.  
  194.     case WM_TIMER:
  195.         ASSERT( NULL != pmw );
  196.         if (!pmw->OnTimer(wParam, lParam))
  197.         return(DefWindowProc(hWnd, message, wParam, lParam));
  198.         break;
  199.  
  200.     case WM_DROPFILES:
  201.         ASSERT( NULL != pmw );
  202.         if( !pmw->OnDropFiles( wParam ))
  203.         return(DefWindowProc(hWnd, message, wParam, lParam));
  204.         break;
  205.  
  206.     case WM_PAINT:
  207.         ASSERT( NULL != pmw );
  208.         if( !pmw->OnPaint(wParam, lParam))
  209.         return(DefWindowProc(hWnd, message, wParam, lParam));
  210.         break;
  211.  
  212.     case WM_INITMENU:
  213.         ASSERT( NULL != pmw );
  214.         if((HMENU)wParam != GetMenu( hWnd ))
  215.         break;
  216.         return pmw->OnInitMenu( wParam );
  217.         break;
  218.  
  219.     case WM_COMMAND:
  220.         ASSERT( NULL != pmw );
  221.         if (!pmw->OnCommand(wParam, lParam))
  222.         return DefWindowProc(hWnd, message, wParam, lParam);
  223.         break;
  224.  
  225.     case WM_DESTROY:
  226.         ASSERT( NULL != pmw );
  227.         pmw->OnDestroy();
  228.         PostQuitMessage(0);
  229.         break;
  230.  
  231.     default:
  232.         return DefWindowProc( hWnd, message, wParam, lParam );
  233.         break;
  234.     }
  235.  
  236.     return 0L;
  237. }
  238.  
  239.  
  240. BOOL MainWnd::OnInitMenu( WPARAM wParam )
  241. {
  242.     int i;
  243.  
  244.     CheckMenuItem( (HMENU)wParam,
  245.            CommandIDFromFormatCode( gdwOutputFormat ),
  246.            MF_BYCOMMAND | MF_CHECKED );
  247.  
  248.     for( i = 0; i < NUM_FORMATENTRIES; i++ )
  249.     {
  250.     if( !fdFormats[i].fEnable )
  251.         EnableMenuItem((HMENU)wParam,
  252.                CommandIDFromFormatCode( fdFormats[i].dwCode ),
  253.                MF_BYCOMMAND | MF_GRAYED );
  254.     else
  255.         EnableMenuItem((HMENU)wParam,
  256.                CommandIDFromFormatCode( fdFormats[i].dwCode ),
  257.                MF_BYCOMMAND | MF_ENABLED );
  258.     }
  259.     // If there are no buffers open, then disable the buffers menu
  260.     EnableMenuItem((HMENU)wParam, 2, MF_BYPOSITION |
  261.            (m_dlInfoList.GetElementCount() ? MF_ENABLED : MF_GRAYED));
  262.     return TRUE;
  263. }
  264.  
  265. /* OnDropFiles()
  266.  *
  267.  *    Handles the WM_DROPFILES message, which is a message sent when someone
  268.  * drags and drops files onto our application window.
  269.  */
  270. BOOL MainWnd::OnDropFiles( WPARAM wParam )
  271. {
  272.     WORD    wNumFiles = DragQueryFile((HDROP)wParam, (UINT)-1, NULL, (UINT)0 );
  273.     WORD    nFile, nPathLength;
  274.     LPSTR   lpszFile;
  275.  
  276.     for( nFile = 0; nFile < wNumFiles; nFile++ )
  277.     {
  278.     nPathLength = DragQueryFile((HDROP)wParam, nFile, NULL, 0 ) + 1;
  279.     if(( lpszFile = new char[nPathLength] ) == NULL )
  280.         continue;
  281.     DragQueryFile((HDROP)wParam, nFile, lpszFile, nPathLength );
  282.     
  283.     // Open the file
  284.     OnFileOpen( lpszFile );
  285.     
  286.     delete[] lpszFile;
  287.     }
  288.  
  289.     DragFinish((HDROP)wParam);
  290.     return TRUE;
  291. }
  292.  
  293.  
  294. /* OnCommand()
  295.  *
  296.  *    WM_COMMAND message handler for the main window procedure.
  297.  */
  298. BOOL MainWnd::OnCommand( WPARAM wParam, LPARAM lParam )
  299. {
  300.     HRESULT hr;
  301.     DWORD   dwNewFormat;
  302.     int     i = 0;
  303.  
  304.     if(( dwNewFormat = FormatCodeFromCommandID( LOWORD(wParam))) != 0 )
  305.     {
  306.     CheckMenuItem( GetMenu( m_hwnd ),
  307.                 CommandIDFromFormatCode( gdwOutputFormat ),
  308.                 MF_BYCOMMAND | MF_UNCHECKED );
  309.     FormatCodeToWFX( dwNewFormat, gpwfxFormat );
  310.     DPF( 2, "Setting output format to code: %lu", dwNewFormat );
  311.     hr = gpdsbPrimary->SetFormat( gpwfxFormat );
  312.     if( SUCCEEDED( hr ))
  313.         gdwOutputFormat = dwNewFormat;
  314.     else
  315.         {
  316.         DisableFormatCode( dwNewFormat );
  317.         EnableMenuItem( GetMenu( m_hwnd ),
  318.                 CommandIDFromFormatCode( dwNewFormat ),
  319.                 MF_BYCOMMAND | MF_GRAYED );
  320.         FormatCodeToWFX( gdwOutputFormat, gpwfxFormat );
  321.         gpdsbPrimary->SetFormat( gpwfxFormat );
  322.         }
  323.     return TRUE;
  324.     }
  325.  
  326.     switch( LOWORD(wParam))
  327.     {
  328.     case IDC_FILE_EXIT:
  329.         PostMessage(WM_CLOSE, 0, 0);
  330.         break;
  331.  
  332.     case IDC_FILE_OPEN:
  333.         OnFileOpen( NULL );
  334.         UpdateStatus();
  335.         break;
  336.  
  337.     case IDC_OPTIONS_SETTINGS:
  338.         DialogBox(ghInst, MAKEINTRESOURCE(IDD_SETTINGS),
  339.                         m_hwnd, (DLGPROC)SettingsDlgProc);
  340.         UpdateStatus();
  341.         break;
  342.  
  343.     case IDC_BUFFERS_MINIMIZEALL:
  344.         m_dlInfoList.SetAtHead();
  345.         for( i = 0; i < m_dlInfoList.GetElementCount(); i++)
  346.         {
  347.         m_dlInfoList.GetCurrent()->MinimizeWindow();
  348.         m_dlInfoList++;
  349.         }
  350.         break;
  351.  
  352.     case IDC_BUFFERS_RESTOREALL:
  353.         m_dlInfoList.SetAtHead();
  354.         for( i = 0; i < m_dlInfoList.GetElementCount(); i++)
  355.         {
  356.         m_dlInfoList.GetCurrent()->RestoreWindow();
  357.         m_dlInfoList++;
  358.         }
  359.         break;
  360.  
  361.     case IDC_BUFFERS_CLOSEALL:
  362.         while( m_dlInfoList.GetElementCount())
  363.         {
  364.         m_dlInfoList.SetAtHead();
  365.         m_dlInfoList.GetCurrent()->Close();
  366.         // Element is removed from the list by processing elsewhere
  367.         }
  368.         EnableMenuItem(GetMenu(m_hwnd), 2, MF_BYPOSITION |
  369.                (m_dlInfoList.GetElementCount() ? MF_ENABLED : MF_GRAYED));
  370.         DrawMenuBar( m_hwnd );
  371.         break;
  372.  
  373.     case IDC_BUFFERS_CASCADE:
  374.         m_dlInfoList.SetAtHead();
  375.         for( i = 0; i < m_dlInfoList.GetElementCount(); i++)
  376.         {
  377.         if( 0 == i )
  378.             m_dlInfoList.GetCurrent()->ResetCascade();
  379.         m_dlInfoList.GetCurrent()->CascadeWindow();
  380.         m_dlInfoList++;
  381.         }
  382.         break;
  383.  
  384.     case IDC_HELP_ABOUT:
  385.         DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT),
  386.                         m_hwnd, (DLGPROC)AboutDlgProc);
  387.         break;
  388.  
  389.     default:
  390.         return FALSE;
  391.     }
  392.  
  393.     /* If we broke out of the switch, it means we handled the message
  394.      * so we return TRUE to indicate this.
  395.      */
  396.     return TRUE;
  397. }
  398.  
  399.  
  400. /* DuplicateBuffer()
  401.  *
  402.  *    Does the work of duplicating a FileInfo object.
  403.  */
  404. void MainWnd::DuplicateBuffer( FileInfo *pfiSource )
  405. {
  406.     FileInfo    *pfiNew;
  407.  
  408.     if( NULL == pfiSource )
  409.     return;
  410.  
  411.     if( m_dlInfoList.GetElementCount() >= MAXCONTROLS )
  412.     {
  413.     MessageBox( "No more controls allowed" );
  414.         return;
  415.     }
  416.  
  417.     if( pfiSource->Is3D())
  418.     {
  419.     m_n3DBuffers++;
  420.     pfiNew = new FileInfo3D( this );
  421.     }
  422.     else
  423.     pfiNew = new FileInfo( this );
  424.  
  425.     if( NULL == pfiNew )
  426.     return;
  427.  
  428.     pfiNew->Duplicate( pfiSource );
  429.     m_dlInfoList.Append( pfiNew );
  430. }
  431.  
  432.  
  433. /* OnFileOpen()
  434.  *
  435.  *    Handles the File|Open menu command.
  436.  */
  437. FileInfo *MainWnd::OnFileOpen( LPSTR lpszForcePath )
  438. {
  439.     char            szFileName[MAX_PATH];
  440.     FileInfo        *pFileInfo = NULL;
  441.     LPSTR       lpszFileTitle;
  442.     int             nFileIndex;
  443.     DWORD       dwFlags;
  444.  
  445.     if( m_dlInfoList.GetElementCount() >= MAXCONTROLS )
  446.     {
  447.     MessageBox( "No more controls allowed" );
  448.         return NULL;
  449.     }
  450.  
  451.     if( NULL != lpszForcePath )
  452.     {
  453.     dwFlags = OPENFILENAME_F_GETPOS2;
  454.     if( grs.dwDefaultFocusFlag & DSBCAPS_STICKYFOCUS )
  455.         dwFlags |= OPENFILENAME_F_STICKYFOCUS;
  456.     else if( grs.dwDefaultFocusFlag & DSBCAPS_GLOBALFOCUS )
  457.         dwFlags |= OPENFILENAME_F_GLOBALFOCUS;
  458.  
  459.     if( grs.fOpen3D )
  460.         dwFlags |= OPENFILENAME_F_3D;
  461.     lpszFileTitle = strrchr( lpszForcePath, '\\' );
  462.     if( NULL == lpszFileTitle )
  463.         nFileIndex = 0;
  464.     else
  465.         nFileIndex =  lpszFileTitle - lpszForcePath + sizeof(char);
  466.     lstrcpy( szFileName, lpszForcePath );
  467.     }
  468.     else
  469.     {
  470.     // Open the file, and check its format, etc.
  471.     if( !OpenFileDialog( m_hwnd, szFileName, &nFileIndex, &dwFlags ))
  472.         return NULL;
  473.     }
  474.  
  475.     // Allocate the memory for the structure.
  476.     if( dwFlags & OPENFILENAME_F_3D )
  477.     {
  478.     pFileInfo = new FileInfo3D( this );
  479.     }
  480.     else
  481.     pFileInfo = new FileInfo( this );
  482.  
  483.     if( NULL == pFileInfo )
  484.     {
  485.     MessageBox( "Cannot add this file -- out of memory",
  486.                             MB_OK|MB_ICONSTOP );
  487.     goto ERROR_DONE_ROUTINE;
  488.     }
  489.  
  490.     if( m_dlInfoList.GetElementCount() == 0 )
  491.     pFileInfo->ResetCascade();
  492.  
  493.     m_dlInfoList.Append( pFileInfo );
  494.  
  495.     pFileInfo->SetSticky((dwFlags & OPENFILENAME_F_STICKYFOCUS)
  496.                             ? TRUE : FALSE );
  497.     pFileInfo->SetGlobal((dwFlags & OPENFILENAME_F_GLOBALFOCUS)
  498.                             ? TRUE : FALSE );
  499.     pFileInfo->Set3D((dwFlags & OPENFILENAME_F_3D) ? TRUE : FALSE );
  500.     pFileInfo->SetUseGetPos2((dwFlags & OPENFILENAME_F_GETPOS2)
  501.                             ? TRUE : FALSE );
  502.  
  503.     if( pFileInfo->LoadWave( szFileName, nFileIndex ) != 0 )
  504.     {
  505.     m_dlInfoList.Remove( pFileInfo );
  506.     goto ERROR_DONE_ROUTINE;
  507.     }
  508.  
  509.     // If we fail after this, make sure to update the list!!!
  510.     if( pFileInfo->Is3D())
  511.     {
  512.     if( m_n3DBuffers++ == 0 )
  513.         {
  514.         // We only want to create this dialog once, and if this is the
  515.         // first 3D buffer opened, then there should be no listener DLG yet
  516.         ASSERT( NULL == ghwndListener );
  517.  
  518.         gpListenerInfo = new ListenerInfo;
  519.         ghwndListener = CreateDialogParam( ghInst,
  520.                         MAKEINTRESOURCE(IDD_3DLISTENER),
  521.                         AppWnd.GetHwnd(),
  522.                         (DLGPROC)ListenerInfoDlgProc,
  523.                         (LPARAM)(gpListenerInfo));
  524.         ::ShowWindow( ghwndListener, SW_SHOW );
  525.         }
  526.     }
  527.  
  528.     // If there are no buffers open, then disable the buffers menu
  529.     EnableMenuItem(GetMenu(m_hwnd), 2, MF_BYPOSITION |
  530.            (m_dlInfoList.GetElementCount() ? MF_ENABLED : MF_GRAYED));
  531.     DrawMenuBar( m_hwnd );
  532.  
  533.     return pFileInfo;
  534.  
  535.  
  536. ERROR_DONE_ROUTINE:
  537.     if( pFileInfo != NULL )
  538.     {
  539.     delete pFileInfo;
  540.     pFileInfo = NULL;
  541.     }
  542.     return NULL;
  543. }
  544.  
  545.  
  546. /* DestroyFileInfo()
  547.  *
  548.  *    Destroys a FileInfo structure and removes it from the list.
  549.  */
  550. void MainWnd::DestroyFileInfo( FileInfo *pfi )
  551. {
  552.     if( NULL == pfi )
  553.     return;
  554.  
  555.     if( pfi->Is3D() )
  556.     {
  557.     if( --m_n3DBuffers == 0 )
  558.         {
  559.         ::DestroyWindow( ghwndListener );
  560.         ghwndListener = NULL;
  561.         delete gpListenerInfo;
  562.         gpListenerInfo = NULL;
  563.         }
  564.     }
  565.  
  566.     m_dlInfoList.Remove( pfi );
  567.     delete pfi;
  568.     UpdateStatus();
  569. }
  570.  
  571.  
  572. BOOL MainWnd::OnPaint( WPARAM wParam, LPARAM lParam )
  573.     {
  574.     PAINTSTRUCT ps;
  575.     RECT    rcClient;
  576.     SIZE    sizeExtent;
  577.     char    szText[128];
  578.  
  579.     if( !BeginPaint( m_hwnd, &ps ))
  580.     return FALSE;
  581.  
  582.     GetClientRect( m_hwnd, &rcClient );
  583.     
  584.     SetBkMode( ps.hdc, TRANSPARENT );
  585.  
  586.     wsprintf( szText, "Free HW Mem: %luKb", m_dscaps.dwFreeHwMemBytes / 1024 );
  587.     GetTextExtentPoint32( ps.hdc, szText, lstrlen(szText), &sizeExtent );
  588.     
  589.     DrawText( ps.hdc, szText, -1, &rcClient, DT_TOP | DT_LEFT );
  590.  
  591.     wsprintf( szText, "Free HW Buffers: %lu", m_dscaps.dwFreeHwMixingStaticBuffers );
  592.     rcClient.top += sizeExtent.cy;
  593.     DrawText( ps.hdc, szText, -1, &rcClient, DT_TOP | DT_LEFT );
  594.  
  595.     EndPaint( m_hwnd, &ps );
  596.     return TRUE;
  597.     }
  598.  
  599.  
  600. void MainWnd::UpdateStatus( void )
  601.     {
  602.     if( gpds )
  603.     {
  604.     // Get updated statistics on the DSound device
  605.     gpds->GetCaps( &m_dscaps );
  606.     
  607.     // Force a window client area repaint
  608.     InvalidateRect( m_hwnd, NULL, TRUE );
  609.     UpdateWindow();
  610.     }
  611.     }
  612.  
  613. ////////////////////////////////////////////////////////////////////////////
  614. // BatchOpenFiles()
  615. //
  616. //    Takes an array of string pointers and tries to open each as a file to
  617. // playback.  If fPlay is TRUE, the files will be played as they are being
  618. // opened.  If fLoop is TRUE, they will also be set to loop.
  619. //
  620. // Returns: FALSE in the event of catastrophic failure, otherwise TRUE.
  621. //
  622. BOOL MainWnd::BatchOpenFiles( PSTR *ppszFiles, int nFiles, BOOL fPlay, BOOL fLoop )
  623. {
  624.     FileInfo    *pfi;
  625.     int     i;
  626.  
  627.     // Cap the number of files we can load out of the given set if we'd load
  628.     // too many otherwise
  629.     if( m_dlInfoList.GetElementCount() >= MAXCONTROLS )
  630.     {
  631.     MessageBox( "No more controls allowed" );
  632.         return FALSE;
  633.     }
  634.  
  635.     for( i = 0; i < nFiles; i++ )
  636.     {
  637.     if(( pfi = OnFileOpen( ppszFiles[i] )) == NULL )
  638.         continue;
  639.  
  640.     // LOOP is only obeyed if PLAY was also specified
  641.     if( fPlay )
  642.     {
  643.         if( fLoop )
  644.         {
  645.         pfi->SetLooped( TRUE );
  646.         }
  647.         pfi->PlayBuffer();
  648.     }
  649.  
  650.     pfi->UpdateUI();
  651.     }
  652.  
  653.     return TRUE;
  654. }
  655.  
  656.