//----------------------------------------------------------------------------- // Name: CMusicManager::CreateScriptFromFile() // Desc: //----------------------------------------------------------------------------- HRESULT CMusicManager::CreateScriptFromFile( CMusicScript** ppScript, TCHAR* strFileName ) { HRESULT hr; IDirectMusicScript* pScript = NULL; // DMusic only takes wide strings WCHAR wstrFileName[MAX_PATH]; DXUtil_ConvertGenericStringToWide( wstrFileName, strFileName ); if ( FAILED( hr = m_pLoader->LoadObjectFromFile( CLSID_DirectMusicScript, IID_IDirectMusicScript8, wstrFileName, (LPVOID*) &pScript ) ) ) return DXTRACE_ERR_NOMSGBOX( TEXT("LoadObjectFromFile"), hr ); if ( FAILED( hr = pScript->Init( m_pPerformance, NULL ) ) ) return DXTRACE_ERR( TEXT("Init"), hr ); *ppScript = new CMusicScript( m_pPerformance, m_pLoader, pScript ); if (!*ppScript) return E_OUTOFMEMORY; return hr; }
//----------------------------------------------------------------------------- // Name: OnPlaySound() // Desc: User hit the "Play" button //----------------------------------------------------------------------------- HRESULT OnPlaySound( HWND hDlg ) { HRESULT hr; DWORD dwCreationFlags; DWORD dwResults; LPDIRECTSOUNDBUFFER pDSB = NULL; LPDIRECTSOUNDBUFFER8 pDSB8 = NULL; BOOL bLooped = ( IsDlgButtonChecked( hDlg, IDC_LOOP_CHECK ) == BST_CHECKED ); // We would only use CTRLFX control on dsound buffer dwCreationFlags = DSBCAPS_CTRLFX; // Free any previous sound and FXs SAFE_RELEASE( g_pIGargle ); SAFE_DELETE( g_pSound ); // Since the user can change the focus before the sound is played, // we need to create the sound buffer every time the play button is pressed // Load the wave file into a DirectSound buffer if( FAILED( hr = g_pSoundManager->Create( &g_pSound, g_strWaveFileName, dwCreationFlags, GUID_NULL ) ) ) { // Not a critical failure, so just update the status DXTRACE_ERR_NOMSGBOX( TEXT("Create"), hr ); if( hr == DSERR_BUFFERTOOSMALL ) { // DSERR_BUFFERTOOSMALL will be returned if the buffer is // less than DSBSIZE_FX_MIN (100ms) and the buffer is created // with DSBCAPS_CTRLFX. SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file is too short (less than 100ms) for effect processing.") ); } else { SetDlgItemText( hDlg, IDC_STATUS, TEXT("Could not create sound buffer.") ); } return S_FALSE; } // Query IDirectSoundBuffer8 interface pDSB = g_pSound->GetBuffer( 0 ); if( FAILED( hr = pDSB->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*) &pDSB8 ) ) ) return DXTRACE_ERR( TEXT("QueryInterface"), hr ); // Set gargle effect on the IDirectSoundBuffer8 DSEFFECTDESC dsed; ZeroMemory( &dsed, sizeof(DSEFFECTDESC) ); dsed.dwSize = sizeof(DSEFFECTDESC); dsed.dwFlags = 0; dsed.guidDSFXClass = GUID_DSFX_STANDARD_GARGLE; if( FAILED( hr = pDSB8->SetFX( 1, &dsed, &dwResults ) ) ) { // Not a critical failure, so just update the status DXTRACE_ERR( TEXT("SetFX"), hr ); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Could not set gargle effect.") ); return S_FALSE; } // Get gargle effect friendly interface if( FAILED( hr = pDSB8->GetObjectInPath( GUID_DSFX_STANDARD_GARGLE, 0, IID_IDirectSoundFXGargle, (LPVOID*) &g_pIGargle ) ) ) return DXTRACE_ERR( TEXT("GetObjectInPath"), hr ); // Cleanup SAFE_RELEASE( pDSB8 ); // Set the buffer options to what the sliders are set to OnEffectChanged( hDlg ); // Play the sound DWORD dwLooped = bLooped ? DSBPLAY_LOOPING : 0L; if( FAILED( hr = g_pSound->Play( 0, dwLooped ) ) ) return DXTRACE_ERR( TEXT("Play"), hr ); // Update the UI controls to show the sound as playing EnablePlayUI( hDlg, FALSE ); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Sound playing.") ); return S_OK; }
//----------------------------------------------------------------------------- // Name: CSoundManager::CreateStreaming() // Desc: //----------------------------------------------------------------------------- HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD m_dwNotifySize, HANDLE hNotifyEvent, FileLog* filelog) { HRESULT hr; if( m_pDS == NULL ) return CO_E_NOTINITIALIZED; if( ppStreamingSound == NULL || hNotifyEvent == NULL ) return E_INVALIDARG; LPDIRECTSOUNDBUFFER pDSBuffer = NULL; DWORD dwDSBufferSize = NULL; DSBPOSITIONNOTIFY* aPosNotify = NULL; LPDIRECTSOUNDNOTIFY m_pDSNotify = NULL; // Figure out how big the DSound buffer should be dwDSBufferSize = m_dwNotifySize * dwNotifyCount; // Set up the direct sound buffer. Request the NOTIFY flag, so // that we are notified as the sound buffer plays. Note, that using this flag // may limit the amount of hardware acceleration that can occur. DSBUFFERDESC dsbd; ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) ); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = dwCreationFlags | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2| DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE; dsbd.dwBufferBytes = dwDSBufferSize; dsbd.guid3DAlgorithm = guid3DAlgorithm; //LPWAVEFORMATEX wfx = new WAVEFORMATEX; WAVEFORMATEX wfx; ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = (WORD) m_dwPrimaryChannels; wfx.nSamplesPerSec = m_dwPrimaryFreq; wfx.wBitsPerSample = (WORD) m_dwPrimaryBitRate; wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; dsbd.lpwfxFormat = &wfx; if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) ) { // If wave format isn't then it will return // either DSERR_BADFORMAT or E_INVALIDARG if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG ) return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr ); return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr ); } // Create the notification events, so that we know when to fill // the buffer as the sound plays. if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify, (VOID**)&m_pDSNotify ) ) ) { SAFE_DELETE( aPosNotify ); return DXTRACE_ERR( TEXT("QueryInterface"), hr ); } aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ]; if( aPosNotify == NULL ) return E_OUTOFMEMORY; for( DWORD i = 0; i < dwNotifyCount; i++ ) { aPosNotify[i].dwOffset = (m_dwNotifySize * i) + m_dwNotifySize - 1; aPosNotify[i].hEventNotify = hNotifyEvent; } // Tell DirectSound when to notify us. The notification will come in the from // of signaled events that are handled in WinMain() if( FAILED( hr = m_pDSNotify->SetNotificationPositions( dwNotifyCount, aPosNotify ) ) ) { SAFE_RELEASE( m_pDSNotify ); SAFE_DELETE( aPosNotify ); return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr ); } SAFE_RELEASE( m_pDSNotify ); SAFE_DELETE( aPosNotify ); // Create the sound *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, m_dwNotifySize,hNotifyEvent,filelog); return S_OK; }
//----------------------------------------------------------------------------- // Name: OnOpenSoundFile() // Desc: Called when the user requests to open a sound file //----------------------------------------------------------------------------- VOID OnOpenSoundFile( HWND hDlg ) { GUID guid3DAlgorithm = GUID_NULL; int nResult; HRESULT hr; static TCHAR strFileName[MAX_PATH] = TEXT(""); static TCHAR strPath[MAX_PATH] = TEXT(""); // Setup the OPENFILENAME structure OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL, TEXT("Wave Files\0*.wav\0All Files\0*.*\0\0"), NULL, 0, 1, strFileName, MAX_PATH, NULL, 0, strPath, TEXT("Open Sound File"), OFN_FILEMUSTEXIST|OFN_HIDEREADONLY, 0, 0, TEXT(".wav"), 0, NULL, NULL }; // Get the default media path (something like C:\WINDOWS\MEDIA) if( '\0' == strPath[0] ) { GetWindowsDirectory( strPath, MAX_PATH ); if( strcmp( &strPath[strlen(strPath)], TEXT("\\") ) ) strcat( strPath, TEXT("\\") ); strcat( strPath, TEXT("MEDIA") ); } if( g_pSound ) { g_pSound->Stop(); g_pSound->Reset(); } // Update the UI controls to show the sound as loading a file EnableWindow( GetDlgItem( hDlg, IDC_PLAY ), FALSE); EnableWindow( GetDlgItem( hDlg, IDC_STOP ), FALSE); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Loading file...") ); // Stop the timer while dialogs are displayed g_bAllowMovementTimer = FALSE; // Display the OpenFileName dialog. Then, try to load the specified file if( TRUE != GetOpenFileName( &ofn ) ) { SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") ); g_bAllowMovementTimer = TRUE; return; } SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); // Free any previous sound, and make a new one SAFE_DELETE( g_pSound ); CWaveFile waveFile; waveFile.Open( strFileName, NULL, WAVEFILE_READ ); WAVEFORMATEX* pwfx = waveFile.GetFormat(); if( pwfx == NULL ) { SetDlgItemText( hDlg, IDC_STATUS, TEXT("Invalid wave file format.") ); return; } if( pwfx->nChannels > 1 ) { // Too many channels in wave. Sound must be mono when using DSBCAPS_CTRL3D SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be mono for 3D control.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; } if( pwfx->wFormatTag != WAVE_FORMAT_PCM ) { // Sound must be PCM when using DSBCAPS_CTRL3D SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be PCM for 3D control.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; } // Get the software DirectSound3D emulation algorithm to use // Ask the user for this sample, so display the algorithm dialog box. nResult = (int)DialogBox( NULL, MAKEINTRESOURCE(IDD_3D_ALGORITHM), NULL, AlgorithmDlgProc ); switch( nResult ) { case -1: // User canceled dialog box SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; case 0: // User selected DS3DALG_NO_VIRTUALIZATION guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION; break; case 1: // User selected DS3DALG_HRTF_FULL guid3DAlgorithm = DS3DALG_HRTF_FULL; break; case 2: // User selected DS3DALG_HRTF_LIGHT guid3DAlgorithm = DS3DALG_HRTF_LIGHT; break; } // Load the wave file into a DirectSound buffer hr = g_pSoundManager->Create( &g_pSound, strFileName, DSBCAPS_CTRL3D, guid3DAlgorithm ); if( FAILED( hr ) || hr == DS_NO_VIRTUALIZATION ) { DXTRACE_ERR_NOMSGBOX( TEXT("Create"), hr ); if( DS_NO_VIRTUALIZATION == hr ) { MessageBox( hDlg, "The 3D virtualization algorithm requested is not supported under this " "operating system. It is available only on Windows 2000, Windows ME, and Windows 98 with WDM " "drivers and beyond. Creating buffer with no virtualization.", "DirectSound Sample", MB_OK ); } // Unknown error, but not a critical failure, so just update the status SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Could not create sound buffer.") ); return; } // Get the 3D buffer from the secondary buffer if( FAILED( hr = g_pSound->Get3DBufferInterface( 0, &g_pDS3DBuffer ) ) ) { DXTRACE_ERR( TEXT("Get3DBufferInterface"), hr ); SetDlgItemText( hDlg, IDC_STATUS, TEXT("Could not get 3D buffer.") ); SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") ); return; } // Get the 3D buffer parameters g_dsBufferParams.dwSize = sizeof(DS3DBUFFER); g_pDS3DBuffer->GetAllParameters( &g_dsBufferParams ); // Set new 3D buffer parameters g_dsBufferParams.dwMode = DS3DMODE_HEADRELATIVE; g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE ); DSBCAPS dsbcaps; ZeroMemory( &dsbcaps, sizeof(DSBCAPS) ); dsbcaps.dwSize = sizeof(DSBCAPS); LPDIRECTSOUNDBUFFER pDSB = g_pSound->GetBuffer( 0 ); pDSB->GetCaps( &dsbcaps ); if( ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) != 0 ) SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using hardware mixing.") ); else SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using software mixing.") ); // Update the UI controls to show the sound as the file is loaded SetDlgItemText( hDlg, IDC_FILENAME, strFileName ); EnablePlayUI( hDlg, TRUE ); g_bAllowMovementTimer = TRUE; // Remember the path for next time strcpy( strPath, strFileName ); char* strLastSlash = strrchr( strPath, '\\' ); strLastSlash[0] = '\0'; // Set the slider positions SetSlidersPos( hDlg, 0.0f, 0.0f, ORBIT_MAX_RADIUS, ORBIT_MAX_RADIUS*2.0f ); OnSliderChanged( hDlg ); }
//----------------------------------------------------------------------------- // Name: CWaveFile::Open() // Desc: Opens a wave file for reading //----------------------------------------------------------------------------- HRESULT CPCMFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags ) { HRESULT hr; m_dwFlags = dwFlags; m_bIsReadingFromMemory = FALSE; if( m_dwFlags == WAVEFILE_READ ) { if( strFileName == NULL ) return E_INVALIDARG; SAFE_DELETE_ARRAY( m_pwfx ); m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ ); if( NULL == m_hmmio ) { HRSRC hResInfo; HGLOBAL hResData; DWORD dwSize; VOID* pvRes; // Loading it as a file failed, so try it as a resource if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) ) { if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) ) return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL ); } if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) ) return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL ); if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) ) return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL ); if( NULL == ( pvRes = LockResource( hResData ) ) ) return DXTRACE_ERR( TEXT("LockResource"), E_FAIL ); CHAR* pData = new CHAR[ dwSize ]; memcpy( pData, pvRes, dwSize ); MMIOINFO mmioInfo; ZeroMemory( &mmioInfo, sizeof(mmioInfo) ); mmioInfo.fccIOProc = FOURCC_MEM; mmioInfo.cchBuffer = dwSize; mmioInfo.pchBuffer = (CHAR*) pData; m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ ); } if( FAILED( hr = ReadMMIO() ) ) { // ReadMMIO will fail if its an not a wave file mmioClose( m_hmmio, 0 ); return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr ); } if( FAILED( hr = ResetFile() ) ) return DXTRACE_ERR( TEXT("ResetFile"), hr ); // After the reset, the size of the wav file is m_ck.cksize so store it now m_dwSize = m_ck.cksize; // Calculate the total playing seconds m_dwTotalSeconds = m_dwSize/ m_pwfx->nAvgBytesPerSec; } else { m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE ); if( NULL == m_hmmio ) return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL ); if( FAILED( hr = WriteMMIO( pwfx ) ) ) { mmioClose( m_hmmio, 0 ); return DXTRACE_ERR( TEXT("WriteMMIO"), hr ); } if( FAILED( hr = ResetFile() ) ) return DXTRACE_ERR( TEXT("ResetFile"), hr ); } return hr; }
//----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CDPlay8Client::JoinSession( DWORD num ) { HRESULT hr; IDirectPlay8Address* pHostAddress = NULL; IDirectPlay8Address* pDeviceAddress = NULL; if( m_pDPlay == NULL ) return E_FAIL; DXTRACE( TEXT("MazeClient: Trying to connect to server\n") ); DPN_APPLICATION_DESC dpnAppDesc; ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) ); dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC ); dpnAppDesc.guidApplication = StressMazeAppGUID; dpnAppDesc.guidInstance = m_Sessions[num].guidInstance; EnterCriticalSection( &m_csLock ); // Copy the host and device address pointers, and addref them. // If this is not done, then there is a rare chance that // EnumSessionCallback() may be called during the Connect() call // and destory the address before DirectPlay gets a chance to copy them. pHostAddress = m_pHostAddresses[num]; pHostAddress->AddRef(); pDeviceAddress = m_pDeviceAddresses[num]; pDeviceAddress->AddRef(); LeaveCriticalSection( &m_csLock ); // Connect to the remote host // The enumeration is automatically canceled after Connect is called if( FAILED( hr = m_pDPlay->Connect( &dpnAppDesc, // Application description pHostAddress, // Session host address pDeviceAddress, // Address of device used to connect to the host NULL, NULL, // Security descriptions & credientials (MBZ in DPlay8) NULL, 0, // User data & its size NULL, // Asynchronous connection context (returned with DPNMSG_CONNECT_COMPLETE in async handshaking) NULL, // Asynchronous connection handle (used to cancel connection process) DPNOP_SYNC ) ) ) // Connect synchronously { if( hr == DPNERR_NORESPONSE || hr == DPNERR_ABORTED ) goto LCleanup; // These are possible if the server exits while joining if( hr == DPNERR_INVALIDINSTANCE ) goto LCleanup; // This is possible if the original server exits and another server comes online while we are connecting DXTRACE_ERR_NOMSGBOX( TEXT("Connect"), hr ); goto LCleanup; } m_bSessionLost = FALSE; DXTRACE( TEXT("MazeClient: Connected to server. Enum automatically canceled\n") ); UpdateConnectionInfo(); m_fLastUpdateConnectInfoTime = DXUtil_Timer( TIMER_GETAPPTIME ); LCleanup: SAFE_RELEASE( pHostAddress ); SAFE_RELEASE( pDeviceAddress ); return hr; }
//----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CDPlay8Client::StartSessionEnum( const TCHAR* ipaddress ) { if( NULL == m_pDPlay ) return E_FAIL; DPN_APPLICATION_DESC dpnAppDesc; IDirectPlay8Address* pDP8AddressHost = NULL; IDirectPlay8Address* pDP8AddressLocal = NULL; WCHAR* wszHostName = NULL; HRESULT hr; DWORD dwPort; m_dwNumSessions = 0; if( m_dpnhEnum != NULL ) { // If an enumeration is already running, cancel // it and start a new one. Ignore any errors from CancelAsyncOperation m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 ); m_dpnhEnum = NULL; } // Create the local device address object if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_ALL, IID_IDirectPlay8Address, (LPVOID*) &pDP8AddressLocal ) ) ) { DXTRACE_ERR( TEXT("CoCreateInstance"), hr ); goto LCleanup; } // Set IP service provider if( FAILED( hr = pDP8AddressLocal->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { DXTRACE_ERR( TEXT("SetSP"), hr ); goto LCleanup; } // Create the remote host address object if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_ALL, IID_IDirectPlay8Address, (LPVOID*) &pDP8AddressHost ) ) ) { DXTRACE_ERR( TEXT("CoCreateInstance"), hr ); goto LCleanup; } // Set IP service provider if( FAILED( hr = pDP8AddressHost->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { DXTRACE_ERR( TEXT("SetSP"), hr ); goto LCleanup; } // Maze uses a fixed port, so add it to the host address dwPort = DPMAZESERVER_PORT; hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT, &dwPort, sizeof(dwPort), DPNA_DATATYPE_DWORD ); if( FAILED(hr) ) { DXTRACE_ERR( TEXT("AddComponent"), hr ); goto LCleanup; } // Set the remote host name (if provided) if( ipaddress != NULL && ipaddress[0] != 0 ) { wszHostName = new WCHAR[_tcslen(ipaddress)+1]; DXUtil_ConvertGenericStringToWide( wszHostName, ipaddress ); hr = pDP8AddressHost->AddComponent( DPNA_KEY_HOSTNAME, wszHostName, (wcslen(wszHostName)+1)*sizeof(WCHAR), DPNA_DATATYPE_STRING ); if( FAILED(hr) ) { DXTRACE_ERR( TEXT("AddComponent"), hr ); goto LCleanup; } } ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) ); dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC ); dpnAppDesc.guidApplication = StressMazeAppGUID; // Enumerate all StressMazeApp hosts running on IP service providers hr = m_pDPlay->EnumHosts( &dpnAppDesc, pDP8AddressHost, pDP8AddressLocal, NULL, 0, INFINITE, 0, INFINITE, NULL, &m_dpnhEnum, 0 ); if( hr != DPNERR_PENDING && FAILED(hr) ) { DXTRACE_ERR_NOMSGBOX( TEXT("EnumHosts"), hr ); goto LCleanup; } LCleanup: SAFE_RELEASE( pDP8AddressHost); SAFE_RELEASE( pDP8AddressLocal ); SAFE_DELETE( wszHostName ); return hr; }