/*==========================================================================; * * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: supervis.cpp * Content: Implements a process that oversees the full duplex * testing proceedure, watching for nasty conditions in * the two child processes that are used to implement the * actual tests. This is required because on some older * VXD drivers, attempting full duplex can hang the process * or even (grumble) lock the whole system. * History: * Date By Reason * ============ * 08/19/99 pnewson created * 10/27/99 pnewson change guid members from pointers to structs * 10/28/99 pnewson Bug #114176 updated DVSOUNDDEVICECONFIG struct * 11/04/99 pnewson Bug #115279 - fixed cancel processing * - fixed crash detection * - fixed multiple instance detection * - added HWND to check audio setup * - automatically advance after full duplex test * 11/30/99 pnewson parameter validation and default device mapping * 12/16/99 rodtoll Bug #119584 - Error code cleanup (Renamed runsetup error) * 01/21/2000 pnewson Update for UI revisions * 01/23/2000 pnewson Improvded feedback for fatal errors (millen bug 114508) * 01/24/2000 pnewson Prefix detected bug fix * 01/25/2000 pnewson Added support for DVFLAGS_WAVEIDS * 01/27/2000 rodtoll Updated with API changes * 02/08/2000 rodtoll Bug #131496 - Selecting DVTHRESHOLD_DEFAULT results in voice * never being detected * 03/03/2000 rodtoll Updated to handle alternative gamevoice build. * 03/23/2000 rodtoll Win64 updates * 04/04/2000 pnewson Added support for DVFLAGS_ALLOWBACK * Removed "Already Running" dialog box * 04/19/2000 rodtoll Bug #31106 - Grey out recording sliders when no vol control avail * 04/19/2000 pnewson Error handling cleanup * Clicking Volume button brings volume window to foreground * 04/21/2000 rodtoll Bug #32889 - Does not run on Win2k on non-admin account * Bug #32952 Does not run on Windows 95 w/o IE4 installed * 05/03/2000 pnewson Bug #33878 - Wizard locks up when clicking Next/Cancel during speaker test * 05/17/2000 rodtoll Bug #34045 - Parameter validation error while running TestNet. * rodtoll Bug #34764 - Verifies capture device before render device * 06/28/2000 rodtoll Prefix Bug #38022 * 07/12/2000 rodtoll Bug #31468 - Add diagnostic spew to logfile to show what is failing the HW Wizard * 07/31/2000 rodtoll Bug #39590 - SB16 class soundcards are passing when they should fail * Half duplex code was being ignored in mic test portion. * 08/06/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles. * 08/28/2000 masonb Voice Merge: Changed ccomutil.h to ccomutil.h * 08/31/2000 rodtoll Bug #43804 - DVOICE: dwSensitivity structure member is confusing - should be dwThreshold * 11/29/2000 rodtoll Bug #48348 - DPVOICE: Modify wizard to make use of DirectPlay8 as the transport. * 02/04/2001 simonpow Bug #354859 - Fixes for PREfast spotted problems (Unitialised variables) ***************************************************************************/ #include "dxvtlibpch.h" #ifndef WIN95 #define PROPSHEETPAGE_STRUCT_SIZE sizeof( PROPSHEETPAGE ) #define PROPSHEETHEAD_STRUCT_SIZE sizeof( PROPSHEETHEADER ) #else #define PROPSHEETPAGE_STRUCT_SIZE PROPSHEETPAGE_V1_SIZE #define PROPSHEETHEAD_STRUCT_SIZE PROPSHEETHEADER_V1_SIZE #endif #undef DPF_SUBCOMP #define DPF_SUBCOMP DN_SUBCOMP_VOICE // logical defines for registry values #define REGVAL_NOTRUN 0 #define REGVAL_CRASHED 1 #define REGVAL_FAILED 2 #define REGVAL_PASSED 3 // local typedefs typedef HRESULT (WINAPI *TDirectSoundEnumFnc)(LPDSENUMCALLBACK, LPVOID); // local static functions static HRESULT SupervisorQueryAudioSetup(CSupervisorInfo* psinfo); static HRESULT RunFullDuplexTest(CSupervisorInfo* lpsinfo); static HRESULT DoTests(CSupervisorInfo* lpsinfo); static HRESULT IssueCommands(CSupervisorInfo* lpsinfo); static HRESULT IssueShutdownCommand(CSupervisorIPC* lpipcSupervisor); // callback functions INT_PTR CALLBACK WelcomeProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK AlreadyRunningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK PreviousCrashProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK FullDuplexProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK MicTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK MicTestFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK SpeakerTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK CompleteProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK FullDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK HalfDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); // Thread functions DWORD WINAPI FullDuplexTestThreadProc(LPVOID lpvParam); DWORD WINAPI LoopbackTestThreadProc(LPVOID lpvParam); // Message handlers BOOL WelcomeInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL WelcomeSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL WelcomeBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL WelcomeNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL WelcomeResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexCompleteHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestLoopbackRunningHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestRecordStartHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestFailedRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL MicTestFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL SpeakerTestOutAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL CompleteInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL CompleteSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL CompleteLoopbackEndedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL CompleteFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL CompleteResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL FullDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL HalfDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL HalfDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL HalfDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL HalfDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); BOOL HalfDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo); // globals HINSTANCE g_hResDLLInstance; #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CSupervisorInfo" CSupervisorInfo::CSupervisorInfo() : m_hfTitle(NULL) , m_guidCaptureDevice(GUID_NULL) , m_guidRenderDevice(GUID_NULL) , m_hFullDuplexThread(NULL) , m_hLoopbackThreadExitEvent(NULL) , m_fAbortFullDuplex(FALSE) , m_hLoopbackThread(NULL) , m_hLoopbackShutdownEvent(NULL) , m_fVoiceDetected(FALSE) , m_hwndWizard(NULL) , m_hwndDialog(NULL) , m_hwndProgress(NULL) , m_hwndInputPeak(NULL) , m_hwndOutputPeak(NULL) , m_hwndInputVolumeSlider(NULL) , m_hwndOutputVolumeSlider(NULL) , m_lpdpvc(NULL) , m_hMutex(NULL) , m_uiWaveInDeviceId(0) , m_uiWaveOutDeviceId(0) , m_dwDeviceFlags(0) , m_fLoopbackRunning(FALSE) , m_fCritSecInited(FALSE) { DPF_ENTER(); ZeroMemory(&m_piSndVol32Record, sizeof(PROCESS_INFORMATION)); ZeroMemory(&m_piSndVol32Playback, sizeof(PROCESS_INFORMATION)); ZeroMemory(&m_woCaps, sizeof(WAVEOUTCAPS)); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::~CSupervisorInfo" CSupervisorInfo::~CSupervisorInfo() { if (m_fCritSecInited) { DNDeleteCriticalSection(&m_csLock); } } // this structure is only used by the next two functions, hence // it is declared here for convenince. struct SMoveWindowEnumProcParam { PROCESS_INFORMATION* lppi; int x; int y; BOOL fMoved; }; struct SBringToForegroundEnumProcParam { PROCESS_INFORMATION* lppi; BOOL fFound; }; #undef DPF_MODNAME #define DPF_MODNAME "BringToForegroundWindowProc" BOOL CALLBACK BringToForegroundWindowProc(HWND hwnd, LPARAM lParam) { SBringToForegroundEnumProcParam* param; param = (SBringToForegroundEnumProcParam*)lParam; DPFX(DPFPREP, DVF_INFOLEVEL, "looking for main window for pid: %i", param->lppi->dwProcessId); DWORD dwProcessId; GetWindowThreadProcessId(hwnd, &dwProcessId); DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId); if (dwProcessId == param->lppi->dwProcessId) { TCHAR rgtchClassName[64]; GetClassName(hwnd, rgtchClassName, 64); if (_tcsnicmp(rgtchClassName, _T("Volume Control"), 64) == 0) { if (!SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetWindowPos failed, code: 0x%x", GetLastError()); } else { param->fFound = TRUE; } } return FALSE; } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "BringToForegroundWindowEnumProc" BOOL CALLBACK BringToForegroundWindowEnumProc(HWND hwnd, LPARAM lParam) { SMoveWindowEnumProcParam* param; param = (SMoveWindowEnumProcParam*)lParam; DPFX(DPFPREP, DVF_INFOLEVEL, "looking for main window for pid: 0x%x", param->lppi->dwProcessId); DWORD dwProcessId; GetWindowThreadProcessId(hwnd, &dwProcessId); DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId); if (dwProcessId == param->lppi->dwProcessId) { TCHAR rgtchClassName[64]; GetClassName(hwnd, rgtchClassName, 64); if (_tcsnicmp(rgtchClassName, _T("Volume Control"), 64) == 0) { if (!SetForegroundWindow(hwnd)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetForegroundWindow failed, code: 0x%x", GetLastError()); } } return FALSE; } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "MoveWindowEnumProc" BOOL CALLBACK MoveWindowEnumProc(HWND hwnd, LPARAM lParam) { SMoveWindowEnumProcParam* param; param = (SMoveWindowEnumProcParam*)lParam; DPFX(DPFPREP, DVF_INFOLEVEL, "looking for main window for pid: %i", param->lppi->dwProcessId); DWORD dwProcessId; GetWindowThreadProcessId(hwnd, &dwProcessId); DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId); if (dwProcessId == param->lppi->dwProcessId) { TCHAR rgtchClassName[64]; GetClassName(hwnd, rgtchClassName, 64); if (_tcsnicmp(rgtchClassName, _T("Volume Control"), 64) == 0) { if (!SetWindowPos(hwnd, HWND_TOP, param->x, param->y, 0, 0, SWP_NOSIZE)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetWindowPos failed, code: 0x%x", GetLastError()); } else { param->fMoved = TRUE; } } return FALSE; } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetDeviceFlags" void CSupervisorInfo::SetDeviceFlags( DWORD dwFlags ) { m_dwDeviceFlags = dwFlags; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetDeviceFlags" void CSupervisorInfo::GetDeviceFlags( DWORD *pdwFlags ) { *pdwFlags = m_dwDeviceFlags; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::LaunchWindowsVolumeControl" HRESULT CSupervisorInfo::LaunchWindowsVolumeControl(HWND hwndWizard, BOOL fRecord) { DPF_ENTER(); STARTUPINFO si; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); TCHAR ptcharCommand[64]; PROCESS_INFORMATION* lppi; UINT uiPlayMixerID = 0; UINT uiCaptureMixerID = 0; MMRESULT mmr = MMSYSERR_NOERROR; mmr = mixerGetID( (HMIXEROBJ) (UINT_PTR) m_uiWaveInDeviceId, &uiCaptureMixerID, MIXER_OBJECTF_WAVEIN ); if( mmr != MMSYSERR_NOERROR ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to get capture mixerline mmr=0x%x", mmr ); return DV_OK; } mmr = mixerGetID( (HMIXEROBJ) (UINT_PTR) m_uiWaveOutDeviceId, &uiPlayMixerID, MIXER_OBJECTF_WAVEOUT ); if( mmr != MMSYSERR_NOERROR ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to get playback mixerline mmr=0x%x", mmr ); return DV_OK; } if (fRecord) { _stprintf(ptcharCommand, _T("sndvol32 /R /D %i"), uiCaptureMixerID); lppi = &m_piSndVol32Record; } else { _stprintf(ptcharCommand, _T("sndvol32 /D %i"), uiPlayMixerID); lppi = &m_piSndVol32Playback; } if (lppi->hProcess != NULL) { DWORD dwExitCode; if (GetExitCodeProcess(lppi->hProcess, &dwExitCode) != 0) { if (dwExitCode == STILL_ACTIVE) { // not dead yet! Don't start another copy, // but do bring it to the foreground. SMoveWindowEnumProcParam param; param.lppi = lppi; param.fMoved = FALSE; param.x = 0; param.y = 0; EnumWindows(BringToForegroundWindowEnumProc, (LPARAM)¶m); DPF_EXIT(); return DV_OK; } // The user terminated the process. Close our handles, // and zero the process information structure CloseHandle(lppi->hProcess); CloseHandle(lppi->hThread); ZeroMemory(lppi, sizeof(PROCESS_INFORMATION)); } else { // If GetExitCodeProcess fails, assume the handle // is bad for some reason. Log it, then behave as // if the process was shut down. At worst, we'll // have multiple copies of SndVol32 running around. Diagnostics_Write(DVF_ERRORLEVEL, "GetExitCodeProcess failed, code:0x%x", GetLastError()); // Don't close the handles, they may be bad. If they're // not, the OS will clean 'em up when the wizard exits. ZeroMemory(lppi, sizeof(PROCESS_INFORMATION)); } } if (lppi->hProcess == NULL) { CreateProcess( NULL, ptcharCommand, NULL, NULL, FALSE, 0, NULL, NULL, &si, lppi); DPFX(DPFPREP, DVF_INFOLEVEL, "Launched volume control, pid:%i", lppi->dwProcessId); // Find main window for the process we just created and // move it manually. // // Note the race condition - I have no reliable way to wait until // the main window has been displayed. So, the work around // (a.k.a. HACK) is to keep looking for it for a while. // If it hasn't been found by then, we just give up. It's not // tragic if we don't find it, it just won't be as neat and // tidy, since the window will come up wherever it was last time. // // Note that sndvol32.exe does not accept the STARTF_USEPOSITION // flag on the PROCESS_INFORMATION structure, so I have to do // this hack. // // In an attempt to let the sndvol32.exe get up and running, // I call Sleep to relinquish my timeslice. Sleep(0); RECT rect; if (GetWindowRect(hwndWizard, &rect)) { SMoveWindowEnumProcParam param; param.lppi = lppi; param.fMoved = FALSE; param.x = rect.left; param.y = rect.top; int iOffset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYBORDER); if (m_piSndVol32Record.hProcess == lppi->hProcess) { // This is the recording control. Cascade it // one level down from the wizard main window. param.x += iOffset; param.y += iOffset; } else { // This is the playback control. Cascade it // two levels down from the wizard main window. param.x += iOffset*2; param.y += iOffset*2; } // Make twenty attempts to move the window. // Combined with Sleep(25), this will not // wait for more than 1/2 second before giving up. for (int i = 0; i < 20; ++i) { EnumWindows(MoveWindowEnumProc, (LPARAM)¶m); if (param.fMoved) { // window was moved, break out. break; } // Window was not moved. Wait 25 milliseconds (plus change) // and try again. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Attempt to move sndvol32 window failed"); Sleep(25); } } else { Diagnostics_Write(DVF_ERRORLEVEL, "GetWindowRect failed"); } } DPF_EXIT(); return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CloseWindowEnumProc" BOOL CALLBACK CloseWindowEnumProc(HWND hwnd, LPARAM lParam) { DWORD dwProcessId; DPFX(DPFPREP, DVF_INFOLEVEL, "looking for pid: 0x%p to shutdown", lParam); GetWindowThreadProcessId(hwnd, &dwProcessId); DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId); if (dwProcessId == (DWORD)lParam) { // found it, ask it to close. DPFX(DPFPREP, DVF_INFOLEVEL, "Sending WM_CLOSE to 0x%p", hwnd); SendMessage(hwnd, WM_CLOSE, 0, 0); return FALSE; } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CloseWindowsVolumeControl" HRESULT CSupervisorInfo::CloseWindowsVolumeControl(BOOL fRecord) { DPF_ENTER(); PROCESS_INFORMATION* lppi; if (fRecord) { lppi = &m_piSndVol32Record; } else { lppi = &m_piSndVol32Playback; } if (lppi->hProcess != NULL) { DWORD dwExitCode; if (GetExitCodeProcess(lppi->hProcess, &dwExitCode) != 0) { if (dwExitCode == STILL_ACTIVE) { DPFX(DPFPREP, DVF_INFOLEVEL, "Attempting to close volume control with pid: %i", lppi->dwProcessId); // there is currently a volume control showing, find it and // ask it to close EnumWindows(CloseWindowEnumProc, lppi->dwProcessId); // Zero out the process information struct ZeroMemory(lppi, sizeof(PROCESS_INFORMATION)); } } } DPF_EXIT(); return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetWaveOutVolume" HRESULT CSupervisorInfo::GetWaveOutVolume(DWORD* lpdwVolume) { DPF_ENTER(); if (!(m_woCaps.dwSupport & WAVECAPS_VOLUME|WAVECAPS_LRVOLUME)) { // doesn't support wave out Diagnostics_Write(DVF_ERRORLEVEL, "Wave device %i does not support volume control", m_uiWaveOutDeviceId); DPF_EXIT(); return E_FAIL; } MMRESULT mmr = waveOutGetVolume((HWAVEOUT) ((UINT_PTR) m_uiWaveOutDeviceId ), lpdwVolume); if (mmr != MMSYSERR_NOERROR) { Diagnostics_Write(DVF_ERRORLEVEL, "waveOutGetVolume failed, code: %i", mmr); DPF_EXIT(); return E_FAIL; } if (m_woCaps.dwSupport & WAVECAPS_LRVOLUME) { // has a left and right volume control - average them *lpdwVolume = (HIWORD(*lpdwVolume) + LOWORD(*lpdwVolume))/2; } else { // just a mono control - only the low word is significant *lpdwVolume = LOWORD(*lpdwVolume); } DPF_EXIT(); return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetWaveOutVolume" HRESULT CSupervisorInfo::SetWaveOutVolume(DWORD dwVolume) { DPF_ENTER(); MMRESULT mmr = waveOutSetVolume((HWAVEOUT) ((UINT_PTR) m_uiWaveOutDeviceId), LOWORD(dwVolume)<<16|LOWORD(dwVolume)); if (mmr != MMSYSERR_NOERROR) { DPF_EXIT(); return E_FAIL; } DPF_EXIT(); return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetRecordVolume" HRESULT CSupervisorInfo::SetRecordVolume(LONG lVolume) { HRESULT hr; DVCLIENTCONFIG dvcc; dvcc.dwSize = sizeof(dvcc); if (m_lpdpvc != NULL) { hr = m_lpdpvc->GetClientConfig(&dvcc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "GetClientConfig failed, hr:%i", hr); return hr; } dvcc.lRecordVolume = lVolume; hr = m_lpdpvc->SetClientConfig(&dvcc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetClientConfig failed, hr:%i", hr); return hr; } } else { return DVERR_INVALIDPOINTER; } return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CancelFullDuplexTest" HRESULT CSupervisorInfo::CancelFullDuplexTest() { HRESULT hrFnc; HRESULT hr; DWORD dwRet; LONG lRet; hrFnc = DV_OK; Diagnostics_Write(DVF_ERRORLEVEL,"User cancelled wizard during full duplex test." ); DNEnterCriticalSection(&m_csLock); // Are we currently in the middle of a full duplex test? if (m_hFullDuplexThread != NULL) { // This flag is periodically checked by the full duplex test // while it works. m_fAbortFullDuplex = TRUE; // wait for the full duplex thread to exit gracefully DNLeaveCriticalSection(&m_csLock); dwRet = WaitForMultipleObjects( 1, &m_hFullDuplexThread, FALSE, gc_dwLoopbackTestThreadTimeout); switch (dwRet) { case WAIT_OBJECT_0: // the full duplex thread is now done, so continue... DNEnterCriticalSection(&m_csLock); break; case WAIT_TIMEOUT: // The full duplex thread is not cooperating - get tough with it. DNEnterCriticalSection(&m_csLock); hr = m_sipc.TerminateChildProcesses(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "TerminateChildProcesses failed, code: 0x%x", hr); hrFnc = hr; } if (!TerminateThread(m_hFullDuplexThread, hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "TerminateThread failed, code: 0x%x", lRet); hrFnc = DVERR_GENERIC; } break; default: // this is not supposed to happen. Note it, terminate everything, // and continue. DNEnterCriticalSection(&m_csLock); if (dwRet == WAIT_ABANDONED) { Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject abandoned unexpectedly"); hrFnc = DVERR_GENERIC; } else { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject failed, code: 0x%x", lRet); hrFnc = DVERR_GENERIC; } hr = m_sipc.TerminateChildProcesses(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "TerminateChildProcesses failed, code: 0x%x", hr); hrFnc = hr; } if (!TerminateThread(m_hFullDuplexThread, hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "TerminateThread failed, code: 0x%x", lRet); hrFnc = DVERR_GENERIC; } break; } // Close the full duplex thread handle hr = WaitForFullDuplexThreadExitCode(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "WaitForFullDuplexThreadExitCode failed, code: 0x%x", hr); hrFnc = hr; } // cleanup the IPC objects hr = DeinitIPC(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DeinitIPC failed, code: 0x%x", hr); hrFnc = hr; } } DNLeaveCriticalSection(&m_csLock); return hrFnc; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CancelLoopbackTest" HRESULT CSupervisorInfo::CancelLoopbackTest() { HRESULT hr = DV_OK; Diagnostics_Write(DVF_ERRORLEVEL,"User cancelled wizard during loopback test" ); DNEnterCriticalSection(&m_csLock); // Are we currently in the middle of a loopback test? if (m_hLoopbackThread != NULL) { // If the loopback thread handle is not null, the mic test may still // be going on, in which case we want to set that flag to // REGVAL_NOTRUN, since the test was not completed. DWORD dwRegVal; GetMicDetected(&dwRegVal); if (dwRegVal == REGVAL_CRASHED) { SetMicDetected(REGVAL_NOTRUN); } DNLeaveCriticalSection(&m_csLock); // ShutdownLoopbackThread has its own guard hr = ShutdownLoopbackThread(); DNEnterCriticalSection(&m_csLock); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr); } } DNLeaveCriticalSection(&m_csLock); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::Cancel" HRESULT CSupervisorInfo::Cancel() { DPF_ENTER(); DWORD dwRet; HRESULT hr; LONG lRet; HRESULT hrFnc; BOOL fDone; BOOL fGotMsg; BOOL fWelcomeNext; MSG msg; DNEnterCriticalSection(&m_csLock); hrFnc = DV_OK; // close any open volume controls CloseWindowsVolumeControl(TRUE); CloseWindowsVolumeControl(FALSE); // The cancel button can be hit at any time. // We are not in a known state. This function // has to figure it out from the member variables. // How fun. DNLeaveCriticalSection(&m_csLock); // CancelFullDuplexTest has it's own guard hrFnc = CancelFullDuplexTest(); DNEnterCriticalSection(&m_csLock); // Are we currently in the middle of a loopback test? if (m_hLoopbackThread != NULL) { DNLeaveCriticalSection(&m_csLock); // ShutdownLoopbackThread has its own guard hr = ShutdownLoopbackThread(); DNEnterCriticalSection(&m_csLock); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr); hrFnc = hr; } } // Reset the registry to the "test not yet run" state // but only if the user moved past the welcome page GetWelcomeNext(&fWelcomeNext); if (fWelcomeNext) { hr = SetHalfDuplex(REGVAL_NOTRUN); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetHalfDuplex failed, code: %i", hr); hrFnc = hr; } hr = SetFullDuplex(REGVAL_NOTRUN); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetFullDuplex failed, code: %i", hr); hrFnc = hr; } hr = SetMicDetected(REGVAL_NOTRUN); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetMicDetected failed, code: %i", hr); hrFnc = hr; } } // record the fact that the wizard was bailed out of SetUserCancel(); DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hrFnc; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::Abort" HRESULT CSupervisorInfo::Abort(HWND hDlg, HRESULT hrDlg) { // This is the function called whenever a fatal error is hit while in the wizard DPF_ENTER(); DWORD dwRet; HRESULT hr; LONG lRet; HRESULT hrFnc; BOOL fDone; BOOL fGotMsg; BOOL fWelcomeNext; MSG msg; HWND hwndParent = NULL; hrFnc = DV_OK; // close any open volume controls DNEnterCriticalSection(&m_csLock); CloseWindowsVolumeControl(TRUE); CloseWindowsVolumeControl(FALSE); DNLeaveCriticalSection(&m_csLock); // The cancel button can be hit at any time. // We are not in a known state. This function // has to figure it out from the member variables. // How fun. // CancelFullDuplexTest has it's own guard hrFnc = CancelFullDuplexTest(); // Are we currently in the middle of a loopback test? DNEnterCriticalSection(&m_csLock); if (m_hLoopbackThread != NULL) { DNLeaveCriticalSection(&m_csLock); // ShutdownLoopbackThread has its own guard hr = ShutdownLoopbackThread(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr); hrFnc = hr; } } // Leave the registry alone - this will signal that there was // an error to the next wizard run, assuming we're still in // the middle of a test. If we've actually gotten far enough // along to record a pass in the registry, so be it. // Call EndDialog to forcibly bail out of the wizard. Diagnostics_Write(DVF_ERRORLEVEL, "Attempting to abort wizard, hr: %i", hrDlg); hwndParent = GetParent(hDlg); if (IsWindow(hwndParent)) { PostMessage(hwndParent, WM_CLOSE, (WPARAM)NULL, (LPARAM)NULL); /* // EndDialog does not work because we are in a property sheet if (!EndDialog(hwndParent, hrDlg)) { Diagnostics_Write(DVF_ERRORLEVEL, "EndDialog failed, code: %i:", GetLastError()); } */ } else { Diagnostics_Write(DVF_ERRORLEVEL, "Unable to get a handle to the wizard!"); } DPF_EXIT(); return hrFnc; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::Finish" HRESULT CSupervisorInfo::Finish() { DPF_ENTER(); DWORD dwRet; HRESULT hr; LONG lRet; HRESULT hrFnc; DWORD dwValue; DNEnterCriticalSection(&m_csLock); hrFnc = DV_OK; // close any open volume controls CloseWindowsVolumeControl(TRUE); CloseWindowsVolumeControl(FALSE); DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hrFnc; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CreateFullDuplexThread" HRESULT CSupervisorInfo::CreateFullDuplexThread() { DPF_ENTER(); HRESULT hr; LONG lRet; DWORD dwThreadId; DNEnterCriticalSection(&m_csLock); // Null out the interface pointer m_lpdpvc = NULL; if (m_hFullDuplexThread != NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "m_hFullDuplexThread not NULL"); hr = DVERR_GENERIC; goto error_cleanup; } m_hFullDuplexThread = CreateThread(NULL, 0, FullDuplexTestThreadProc, (LPVOID)this, NULL, &dwThreadId); if (m_hFullDuplexThread == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateThread failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::WaitForFullDuplexThreadExitCode" HRESULT CSupervisorInfo::WaitForFullDuplexThreadExitCode() { DPF_ENTER(); HRESULT hr; HRESULT hrFnc; LONG lRet; DWORD dwThreadId; DWORD dwRet; DNEnterCriticalSection(&m_csLock); if (m_hFullDuplexThread == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "m_hFullDuplexThread is NULL"); hr = DVERR_GENERIC; goto error_cleanup; } dwRet = WaitForSingleObject(m_hFullDuplexThread, gc_dwChildWaitTimeout); switch(dwRet) { case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: Diagnostics_Write(DVF_ERRORLEVEL, "Timed out waiting for full duplex test thread to exit - terminating forcibly"); TerminateThread(m_hFullDuplexThread, DVERR_GENERIC); hr = DVERR_GENERIC; goto error_cleanup; default: Diagnostics_Write(DVF_ERRORLEVEL, "Unknown error waiting for full duplex test thread to exit - terminating forcibly"); TerminateThread(m_hFullDuplexThread, DVERR_GENERIC); hr = DVERR_GENERIC; goto error_cleanup; } if (!GetExitCodeThread(m_hFullDuplexThread, (DWORD*)&hrFnc)) { Diagnostics_Write(DVF_ERRORLEVEL, "Error retrieving full duplex test thread's exit code"); hr = DVERR_GENERIC; goto error_cleanup; } if (!CloseHandle(m_hFullDuplexThread)) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } m_hFullDuplexThread = NULL; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hrFnc; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CreateLoopbackThread" HRESULT CSupervisorInfo::CreateLoopbackThread() { DPF_ENTER(); HRESULT hr; LONG lRet; DWORD dwThreadId; DNEnterCriticalSection(&m_csLock); m_hLoopbackShutdownEvent = NULL; if (m_hLoopbackThread != NULL) { // The loopback test is already running. // Just dump a warning and return pending. DPFX(DPFPREP, DVF_WARNINGLEVEL, "m_hLoopbackThread not NULL"); hr = DVERR_PENDING; goto error_cleanup; } // create an event the loopback thread signals just before it exits m_hLoopbackThreadExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hLoopbackThreadExitEvent == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateEvent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // create an event the loopback thread listens for to shutdown m_hLoopbackShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hLoopbackShutdownEvent == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateEvent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } m_hLoopbackThread = CreateThread(NULL, 0, LoopbackTestThreadProc, (LPVOID)this, NULL, &dwThreadId); if (m_hLoopbackThread == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateThread failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: if (m_hLoopbackThreadExitEvent != NULL) { CloseHandle(m_hLoopbackThreadExitEvent); m_hLoopbackThreadExitEvent = NULL; } if (m_hLoopbackShutdownEvent != NULL) { CloseHandle(m_hLoopbackShutdownEvent); m_hLoopbackShutdownEvent = NULL; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::WaitForLoopbackShutdownEvent" HRESULT CSupervisorInfo::WaitForLoopbackShutdownEvent() { DPF_ENTER(); HRESULT hr; LONG lRet; DWORD dwThreadId; DWORD dwRet; HANDLE hEvent; DNEnterCriticalSection(&m_csLock); hEvent = m_hLoopbackShutdownEvent; DNLeaveCriticalSection(&m_csLock); dwRet = WaitForSingleObject(hEvent, INFINITE); DNEnterCriticalSection(&m_csLock); switch (dwRet) { case WAIT_OBJECT_0: // expected behavior, continue break; case WAIT_TIMEOUT: Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject timed out unexpectedly"); hr = DVERR_GENERIC; goto error_cleanup; case WAIT_ABANDONED: Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject abandoned unexpectedly"); hr = DVERR_GENERIC; goto error_cleanup; default: lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject returned unknown code, GetLastError(): %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SignalLoopbackThreadDone" HRESULT CSupervisorInfo::SignalLoopbackThreadDone() { DPF_ENTER(); HRESULT hr; LONG lRet; HANDLE hEvent; DNEnterCriticalSection(&m_csLock); hEvent = m_hLoopbackThreadExitEvent; DNLeaveCriticalSection(&m_csLock); if (!SetEvent(hEvent)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "SetEvent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DPF_EXIT(); return DV_OK; error_cleanup: DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ShutdownLoopbackThread" HRESULT CSupervisorInfo::ShutdownLoopbackThread() { DPF_ENTER(); HRESULT hr; LONG lRet; DWORD dwThreadId; DWORD dwRet; BOOL fDone; BOOL fGotMsg; MSG msg; HANDLE rghHandle[2]; HANDLE hEvent; DNEnterCriticalSection(&m_csLock); if (m_hLoopbackThread == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "m_hLoopbackThread is NULL"); hr = DVERR_GENERIC; goto error_cleanup; } if (!SetEvent(m_hLoopbackShutdownEvent)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "SetEvent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } /* rghHandle[0] = m_hLoopbackThreadExitEvent; rghHandle[1] = m_hLoopbackThread; */ hEvent = m_hLoopbackThreadExitEvent; DNLeaveCriticalSection(&m_csLock); fDone = FALSE; while (!fDone) { dwRet = WaitForSingleObject(hEvent, gc_dwLoopbackTestThreadTimeout); switch(dwRet) { case WAIT_OBJECT_0: DNEnterCriticalSection(&m_csLock); fDone = TRUE; break; case WAIT_ABANDONED: default: // not supposed to be possible, but treat both like a timeout. case WAIT_TIMEOUT: DNEnterCriticalSection(&m_csLock); hr = DVERR_TIMEOUT; goto error_cleanup; break; } /* dwRet = MsgWaitForMultipleObjects(2, rghHandle, FALSE, gc_dwLoopbackTestThreadTimeout, QS_ALLINPUT); switch (dwRet) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: // expected result, continue... DNEnterCriticalSection(&m_csLock); fDone = TRUE; break; case WAIT_TIMEOUT: // loopback thread is not behaving, jump to // the error block where it will be terminated forcibly DNEnterCriticalSection(&m_csLock); hr = DVERR_TIMEOUT; goto error_cleanup; break; case WAIT_OBJECT_0 + 2: // One or more windows messages have been posted to this thread's // message queue. Deal with 'em. fGotMsg = TRUE; while( fGotMsg ) { fGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); if( fGotMsg ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } break; default: if (dwRet == WAIT_ABANDONED) { Diagnostics_Write(DVF_ERRORLEVEL, "MsgWaitForMultipleObjects abandoned unexpectedly"); } else { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "MsgWaitForMultipleObjects failed, code: %i"); } DNEnterCriticalSection(&m_csLock); hr = DVERR_TIMEOUT; goto error_cleanup; break; } */ } if (!CloseHandle(m_hLoopbackThread)) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); m_hLoopbackThread = NULL; hr = DVERR_GENERIC; goto error_cleanup; } m_hLoopbackThread = NULL; if (!CloseHandle(m_hLoopbackThreadExitEvent)) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); m_hLoopbackThreadExitEvent = NULL; hr = DVERR_GENERIC; goto error_cleanup; } m_hLoopbackThreadExitEvent = NULL; if (!CloseHandle(m_hLoopbackShutdownEvent)) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); m_hLoopbackShutdownEvent = NULL; hr = DVERR_GENERIC; goto error_cleanup; } m_hLoopbackShutdownEvent = NULL; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: if (m_hLoopbackThread != NULL) { TerminateThread(m_hLoopbackThread, DVERR_GENERIC); CloseHandle(m_hLoopbackThread); m_hLoopbackThread = NULL; } if (m_hLoopbackThreadExitEvent != NULL) { CloseHandle(m_hLoopbackThreadExitEvent); m_hLoopbackThreadExitEvent = NULL; } if (m_hLoopbackShutdownEvent != NULL) { CloseHandle(m_hLoopbackShutdownEvent); m_hLoopbackShutdownEvent = NULL; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetFullDuplex" HRESULT CSupervisorInfo::SetFullDuplex(DWORD dwFullDuplex) { DPF_ENTER(); HRESULT hr = DV_OK; HKEY hk; LONG lRet; DNEnterCriticalSection(&m_csLock); if (!m_creg.WriteDWORD(gc_wszValueName_FullDuplex, dwFullDuplex)) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::WriteDWORD failed"); hr = DVERR_GENERIC; } else { // Flush the registry operations to ensure they // are written. Otherwise we may not detect a crash! hk = m_creg.GetHandle(); lRet = RegFlushKey(hk); if (lRet != ERROR_SUCCESS) { Diagnostics_Write(DVF_ERRORLEVEL, "RegFlushKey failed"); hr = DVERR_GENERIC; } } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetFullDuplex" HRESULT CSupervisorInfo::GetFullDuplex(DWORD* pdwFullDuplex) { DPF_ENTER(); HRESULT hr = DV_OK; DNEnterCriticalSection(&m_csLock); if (!m_creg.ReadDWORD(gc_wszValueName_FullDuplex, *pdwFullDuplex)) { // registry key is not present *pdwFullDuplex = 0; hr = DVERR_GENERIC; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHalfDuplex" HRESULT CSupervisorInfo::SetHalfDuplex(DWORD dwHalfDuplex) { DPF_ENTER(); HRESULT hr = DV_OK; LONG lRet; HKEY hk; DNEnterCriticalSection(&m_csLock); if (!m_creg.WriteDWORD(gc_wszValueName_HalfDuplex, dwHalfDuplex)) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::WriteDWORD failed"); hr = DVERR_GENERIC; } else { // Flush the registry operations to ensure they // are written. Otherwise we may not detect a crash! hk = m_creg.GetHandle(); lRet = RegFlushKey(hk); if (lRet != ERROR_SUCCESS) { Diagnostics_Write(DVF_ERRORLEVEL, "RegFlushKey failed"); hr = DVERR_GENERIC; } } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHalfDuplex" HRESULT CSupervisorInfo::GetHalfDuplex(DWORD* pdwHalfDuplex) { DPF_ENTER(); HRESULT hr = DV_OK; DNEnterCriticalSection(&m_csLock); if (!m_creg.ReadDWORD(gc_wszValueName_HalfDuplex, *pdwHalfDuplex)) { // registry key is not present *pdwHalfDuplex = 0; hr = DVERR_GENERIC; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetMicDetected" HRESULT CSupervisorInfo::SetMicDetected(DWORD dwMicDetected) { DPF_ENTER(); HRESULT hr = DV_OK; LONG lRet; HKEY hk; DNEnterCriticalSection(&m_csLock); if (!m_creg.WriteDWORD(gc_wszValueName_MicDetected, dwMicDetected)) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::WriteDWORD failed"); hr = DVERR_GENERIC; } else { // Flush the registry operations to ensure they // are written. Otherwise we may not detect a crash! hk = m_creg.GetHandle(); lRet = RegFlushKey(hk); if (lRet != ERROR_SUCCESS) { Diagnostics_Write(DVF_ERRORLEVEL, "RegFlushKey failed"); hr = DVERR_GENERIC; } } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetMicDetected" HRESULT CSupervisorInfo::GetMicDetected(DWORD* pdwMicDetected) { DPF_ENTER(); HRESULT hr = DV_OK; DNEnterCriticalSection(&m_csLock); if (!m_creg.ReadDWORD(gc_wszValueName_MicDetected, *pdwMicDetected)) { // registry key is not present *pdwMicDetected = 0; hr = DVERR_GENERIC; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::QueryFullDuplex" HRESULT CSupervisorInfo::QueryFullDuplex() { DPF_ENTER(); HRESULT hr; DWORD dwFullDuplex; DWORD dwHalfDuplex; DWORD dwMicDetected; DNEnterCriticalSection(&m_csLock); if (!m_creg.ReadDWORD(gc_wszValueName_HalfDuplex, dwHalfDuplex)) { // registry key is not present - setup has not run DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex key not found in registry"); hr = DVERR_RUNSETUP; goto error_cleanup; } switch (dwHalfDuplex) { case REGVAL_NOTRUN: // test not run DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = 0; test not run"); hr = DVERR_RUNSETUP; goto error_cleanup; case REGVAL_CRASHED: // test crashed out! DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = 1; test crashed"); hr = DVERR_SOUNDINITFAILURE; goto error_cleanup; case REGVAL_FAILED: // test failed gracefully DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = 2; test failed gracefully"); hr = DVERR_SOUNDINITFAILURE; goto error_cleanup; case REGVAL_PASSED: // test passed DPFX(DPFPREP, DVF_INFOLEVEL, "HalfDuplex = 3; test passed"); break; default: // bad key value - return run setup DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = %i; bad key value!", dwHalfDuplex); hr = DVERR_RUNSETUP; goto error_cleanup; } if (!m_creg.ReadDWORD(gc_wszValueName_FullDuplex, dwFullDuplex)) { // registry key is not present - very odd. // however, since we at least passed half duplex to get // here, we'll return half duplex DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex key not found in registry"); hr = DV_HALFDUPLEX; goto error_cleanup; } switch (dwFullDuplex) { case REGVAL_NOTRUN: // Test not run - this is very odd, considering that // in order to get here, the half duplex test must have // been run and passed. Return half duplex. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = 0; test not run"); hr = DV_HALFDUPLEX; goto error_cleanup; case REGVAL_CRASHED: // test crashed out! - They tried, and going further // wouldn't help, so certify them for half duplex DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = 1; test crashed"); hr = DV_HALFDUPLEX; goto error_cleanup; case REGVAL_FAILED: // test failed gracefully - mic test would not have been // run, certify them for half duplex. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = 2; test failed gracefully"); hr = DV_HALFDUPLEX; goto error_cleanup; case REGVAL_PASSED: // test passed DPFX(DPFPREP, DVF_INFOLEVEL, "FullDuplex = 3; test passed"); break; default: // bad key value - but the system can at least do // half duplex, so certify them for half duplex DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = %i; bad key value!", dwFullDuplex); hr = DV_HALFDUPLEX; goto error_cleanup; } // From this point on, we know the full duplex test was ok. // However, in order to get a full duplex pass, the mic must // also have been detected. if (!m_creg.ReadDWORD(gc_wszValueName_MicDetected, dwMicDetected)) { // registry key is not present - very odd DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected key not found in registry"); hr = DV_HALFDUPLEX; goto error_cleanup; } switch (dwMicDetected) { case REGVAL_NOTRUN: // Test not run - odd, but pass them for half duplex anyway DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = 0; test not run"); hr = DV_HALFDUPLEX; goto error_cleanup; case REGVAL_CRASHED: // test crashed out! This shouldn't happen, since it // should have been caught in the full duplex test, // but either way, they tried thier best and half // duplex worked, so certify them for half duplex. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = 1; test crashed"); hr = DV_HALFDUPLEX; goto error_cleanup; case REGVAL_FAILED: // test failed gracefully - certify for half duplex DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = 2; test failed gracefully"); hr = DV_HALFDUPLEX; goto error_cleanup; case REGVAL_PASSED: // test passed DPFX(DPFPREP, DVF_INFOLEVEL, "MicDetected = 3; test passed"); break; default: // bad key value - odd, but pass them for half duplex anyway. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = %i; bad key value!", dwMicDetected); hr = DV_HALFDUPLEX; goto error_cleanup; } // If we get here, all keys were a clean pass, so return full duplex hr = DV_FULLDUPLEX; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::OpenRegKey" HRESULT CSupervisorInfo::OpenRegKey(BOOL fCreate) { DPF_ENTER(); LONG lRet; HRESULT hr; CRegistry cregAudioConfig; HKEY hkAudioConfig; CRegistry cregRender; HKEY hkRender; WCHAR wszRenderGuidString[GUID_STRING_LEN]; WCHAR wszCaptureGuidString[GUID_STRING_LEN]; BOOL bAudioKeyOpen = FALSE; BOOL bRenderKeyOpen = FALSE; DNEnterCriticalSection(&m_csLock); if (!cregAudioConfig.Open(HKEY_CURRENT_USER, gc_wszKeyName_AudioConfig, FALSE, fCreate)) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Open failed"); hr = DVERR_GENERIC; goto error_cleanup; } bAudioKeyOpen = TRUE; hkAudioConfig = cregAudioConfig.GetHandle(); if (!cregRender.Open(hkAudioConfig, &m_guidRenderDevice, FALSE, fCreate)) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Open failed"); hr = DVERR_GENERIC; goto error_cleanup; } bRenderKeyOpen = TRUE; hkRender = cregRender.GetHandle(); if (!m_creg.Open(hkRender, &m_guidCaptureDevice, FALSE, fCreate)) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Open failed"); hr = DVERR_GENERIC; goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return S_OK; error_cleanup: if (bRenderKeyOpen) { cregRender.Close(); } if (bAudioKeyOpen) { cregAudioConfig.Close(); } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ThereCanBeOnlyOne" HRESULT CSupervisorInfo::ThereCanBeOnlyOne() { DPF_ENTER(); LONG lRet; HANDLE hMutex; HRESULT hr; hr = DV_OK; hMutex = CreateMutex(NULL, FALSE, gc_szMutexName); lRet = GetLastError(); if (hMutex == NULL) { // something went very wrong Diagnostics_Write(DVF_ERRORLEVEL, "CreateMutex failed, code: %i", lRet); return DVERR_GENERIC; } // see if the mutex already existed if (lRet == ERROR_ALREADY_EXISTS) { Diagnostics_Write(DVF_ERRORLEVEL, "Detected another instance of test running"); if (!CloseHandle(hMutex)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); } return DVERR_ALREADYPENDING; } DNEnterCriticalSection(&m_csLock); if (m_hMutex != NULL) { DNLeaveCriticalSection(&m_csLock); Diagnostics_Write(DVF_ERRORLEVEL, "m_hMutex not null"); if (!CloseHandle(hMutex)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); } return DVERR_GENERIC; } m_hMutex = hMutex; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CloseMutex" void CSupervisorInfo::CloseMutex() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); LONG lRet; // close the mutex if (!CloseHandle(m_hMutex)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet); } m_hMutex = NULL; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetVoiceDetected" void CSupervisorInfo::SetVoiceDetected() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fVoiceDetected = TRUE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ClearVoiceDetected" void CSupervisorInfo::ClearVoiceDetected() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fVoiceDetected = FALSE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetVoiceDetected" void CSupervisorInfo::GetVoiceDetected(BOOL* lpfPreviousCrash) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lpfPreviousCrash = m_fVoiceDetected; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetUserBack" void CSupervisorInfo::SetUserBack() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fUserBack = TRUE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ClearUserBack" void CSupervisorInfo::ClearUserBack() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fUserBack = FALSE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetUserBack" void CSupervisorInfo::GetUserBack(BOOL* lpfUserBack) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lpfUserBack = m_fUserBack; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetUserCancel" void CSupervisorInfo::SetUserCancel() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fUserCancel = TRUE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ClearUserCancel" void CSupervisorInfo::ClearUserCancel() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fUserCancel = FALSE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetUserCancel" void CSupervisorInfo::GetUserCancel(BOOL* lpfUserCancel) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lpfUserCancel = m_fUserCancel; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetWelcomeNext" void CSupervisorInfo::SetWelcomeNext() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fWelcomeNext = TRUE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ClearWelcomeNext" void CSupervisorInfo::ClearWelcomeNext() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fWelcomeNext = FALSE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetWelcomeNext" void CSupervisorInfo::GetWelcomeNext(BOOL* lpfWelcomeNext) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lpfWelcomeNext = m_fWelcomeNext; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetError" void CSupervisorInfo::GetError(HRESULT* hr) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *hr = m_hrError; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetError" void CSupervisorInfo::SetError(HRESULT hr) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hrError = hr; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetTitleFont" void CSupervisorInfo::GetTitleFont(HFONT* lphfTitle) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphfTitle = m_hfTitle; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetBoldFont" void CSupervisorInfo::GetBoldFont(HFONT* lphfBold) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphfBold = m_hfBold; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetCaptureDevice" void CSupervisorInfo::GetCaptureDevice(GUID* lpguidCaptureDevice) { DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter"); DNEnterCriticalSection(&m_csLock); *lpguidCaptureDevice = m_guidCaptureDevice; DNLeaveCriticalSection(&m_csLock); DPFX(DPFPREP, DVF_ENTRYLEVEL, "Exit"); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetCaptureDevice" void CSupervisorInfo::SetCaptureDevice(GUID guidCaptureDevice) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_guidCaptureDevice = guidCaptureDevice; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetRenderDevice" void CSupervisorInfo::GetRenderDevice(GUID* lpguidRenderDevice) { DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter"); DNEnterCriticalSection(&m_csLock); *lpguidRenderDevice = m_guidRenderDevice; DNLeaveCriticalSection(&m_csLock); DPFX(DPFPREP, DVF_ENTRYLEVEL, "Exit"); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetRenderDevice" void CSupervisorInfo::SetRenderDevice(GUID guidRenderDevice) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_guidRenderDevice = guidRenderDevice; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetWaveOutId" HRESULT CSupervisorInfo::SetWaveOutId(UINT ui) { HRESULT hr = DV_OK; DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_uiWaveOutDeviceId = ui; ZeroMemory(&m_woCaps, sizeof(WAVEOUTCAPS)); MMRESULT mmr = waveOutGetDevCaps(ui, &m_woCaps, sizeof(WAVEOUTCAPS)); if (mmr != MMSYSERR_NOERROR) { ZeroMemory(&m_woCaps, sizeof(WAVEOUTCAPS)); hr = DVERR_INVALIDPARAM; } //error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetWaveInId" void CSupervisorInfo::SetWaveInId(UINT ui) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_uiWaveInDeviceId = ui; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetLoopbackFlags" void CSupervisorInfo::GetLoopbackFlags(DWORD* pdwFlags) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *pdwFlags = m_dwLoopbackFlags; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetLoopbackFlags" void CSupervisorInfo::SetLoopbackFlags(DWORD dwFlags) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_dwLoopbackFlags = dwFlags; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetCheckAudioSetupFlags" void CSupervisorInfo::GetCheckAudioSetupFlags(DWORD* pdwFlags) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *pdwFlags = m_dwCheckAudioSetupFlags; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetCheckAudioSetupFlags" void CSupervisorInfo::SetCheckAudioSetupFlags(DWORD dwFlags) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_dwCheckAudioSetupFlags = dwFlags; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetFullDuplexResults" void CSupervisorInfo::GetFullDuplexResults(HRESULT* phr) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *phr = m_hrFullDuplexResults; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetFullDuplexResults" void CSupervisorInfo::SetFullDuplexResults(HRESULT hr) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hrFullDuplexResults = hr; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDParent" void CSupervisorInfo::GetHWNDParent(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndParent; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDWizard" void CSupervisorInfo::SetHWNDParent(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndParent = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDWizard" void CSupervisorInfo::GetHWNDWizard(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndWizard; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDWizard" void CSupervisorInfo::SetHWNDWizard(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndWizard = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDDialog" void CSupervisorInfo::GetHWNDDialog(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndDialog; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDDialog" void CSupervisorInfo::SetHWNDDialog(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndDialog = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDProgress" void CSupervisorInfo::GetHWNDProgress(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndProgress; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDProgress" void CSupervisorInfo::SetHWNDProgress(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndProgress = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDInputPeak" void CSupervisorInfo::GetHWNDInputPeak(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndInputPeak; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDInputPeak" void CSupervisorInfo::SetHWNDInputPeak(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndInputPeak = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDOutputPeak" void CSupervisorInfo::GetHWNDOutputPeak(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndOutputPeak; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDOutputPeak" void CSupervisorInfo::SetHWNDOutputPeak(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndOutputPeak = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDInputVolumeSlider" void CSupervisorInfo::GetHWNDInputVolumeSlider(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndInputVolumeSlider; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDInputVolumeSlider" void CSupervisorInfo::SetHWNDInputVolumeSlider(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndInputVolumeSlider = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetInputVolumeSliderPos" void CSupervisorInfo::GetInputVolumeSliderPos(LONG* lpl) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lpl = m_lInputVolumeSliderPos; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetInputVolumeSliderPos" void CSupervisorInfo::SetInputVolumeSliderPos(LONG l) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_lInputVolumeSliderPos = l; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetHWNDOutputVolumeSlider" void CSupervisorInfo::GetHWNDOutputVolumeSlider(HWND* lphwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphwnd = m_hwndOutputVolumeSlider; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetHWNDOutputVolumeSlider" void CSupervisorInfo::SetHWNDOutputVolumeSlider(HWND hwnd) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hwndOutputVolumeSlider = hwnd; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetDPVC" void CSupervisorInfo::GetDPVC(LPDIRECTPLAYVOICECLIENT* lplpdpvc) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lplpdpvc = m_lpdpvc; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetDPVC" void CSupervisorInfo::SetDPVC(LPDIRECTPLAYVOICECLIENT lpdpvc) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_lpdpvc = lpdpvc; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetLoopbackShutdownEvent" void CSupervisorInfo::GetLoopbackShutdownEvent(HANDLE* lphEvent) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lphEvent = m_hLoopbackShutdownEvent; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::SetLoopbackShutdownEvent" void CSupervisorInfo::SetLoopbackShutdownEvent(HANDLE hEvent) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_hLoopbackShutdownEvent = hEvent; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetIPC" void CSupervisorInfo::GetIPC(CSupervisorIPC** lplpsipc) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lplpsipc = &m_sipc; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetAbortFullDuplex" void CSupervisorInfo::GetAbortFullDuplex(BOOL* lpfAbort) { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); *lpfAbort = m_fAbortFullDuplex; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::ClearAbortFullDuplex" void CSupervisorInfo::ClearAbortFullDuplex() { DPF_ENTER(); DNEnterCriticalSection(&m_csLock); m_fAbortFullDuplex = FALSE; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::InitIPC" HRESULT CSupervisorInfo::InitIPC() { DPF_ENTER(); HRESULT hr; // the IPC object has it's own guard... hr = m_sipc.Init(); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::DeinitIPC" HRESULT CSupervisorInfo::DeinitIPC() { DPF_ENTER(); HRESULT hr; // The IPC object has it's own guard... // and this is a safe call even if Init // has not been called hr = m_sipc.Deinit(); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::InitClass" BOOL CSupervisorInfo::InitClass() { if (DNInitializeCriticalSection(&m_csLock)) { m_fCritSecInited = TRUE; return TRUE; } else { return FALSE; } } #undef DPF_MODNAME #define DPF_MODNAME "SupervisorCheckAudioSetup" HRESULT SupervisorCheckAudioSetup( const GUID* lpguidRenderDevice, const GUID* lpguidCaptureDevice, HWND hwndParent, DWORD dwFlags) { DPF_ENTER(); HRESULT hr; LRESULT lRet; HKEY hkDevice = NULL; int iRet; CSupervisorInfo sinfo; CPeakMeterWndClass pmwc; BOOL fFullDuplexPassed; BOOL fVoiceDetected; BOOL fUserCancel; BOOL fUserBack; GUID guidCaptureDevice; GUID guidRenderDevice; BOOL fRegKeyOpen = FALSE; BOOL fWndClassRegistered = FALSE; BOOL fTitleFontCreated = FALSE; BOOL fBoldFontCreated = FALSE; BOOL fMutexOpen = FALSE; if (!sinfo.InitClass()) { return DVERR_OUTOFMEMORY; } // init the globals g_hResDLLInstance = NULL; // validate the HWND, if non null if (hwndParent != NULL && !IsWindow(hwndParent)) { Diagnostics_Write(DVF_ERRORLEVEL, "Invalid (but non-null) Window Handle passed in CheckAudioSetup"); hr = DVERR_INVALIDPARAM; goto error_cleanup; } // validate the flags if (dwFlags & ~(DVFLAGS_QUERYONLY|DVFLAGS_NOQUERY|DVFLAGS_WAVEIDS|DVFLAGS_ALLOWBACK)) { Diagnostics_Write(DVF_ERRORLEVEL, "Invalid flags specified in CheckAudioSetup: %x", dwFlags); hr = DVERR_INVALIDFLAGS; goto error_cleanup; } if (dwFlags & DVFLAGS_QUERYONLY) { if (dwFlags & (DVFLAGS_NOQUERY|DVFLAGS_ALLOWBACK)) { Diagnostics_Write(DVF_ERRORLEVEL, "Invalid flags specified in CheckAudioSetup: %x", dwFlags); hr = DVERR_INVALIDFLAGS; goto error_cleanup; } } // save the flags sinfo.SetCheckAudioSetupFlags(dwFlags); // if the waveid flag was specified, translate the waveid to a guid if (dwFlags & DVFLAGS_WAVEIDS) { hr = DV_MapWaveIDToGUID( FALSE, lpguidRenderDevice->Data1, guidRenderDevice ); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapWaveIDToGUID failed, code: %i", hr); goto error_cleanup; } hr = DV_MapWaveIDToGUID( TRUE, lpguidCaptureDevice->Data1, guidCaptureDevice ); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapWaveIDToGUID failed, code: %i", hr); goto error_cleanup; } } else { hr = DV_MapPlaybackDevice(lpguidRenderDevice, &guidRenderDevice); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapPlaybackDevice failed, code: %i", hr); goto error_cleanup; } // map the devices hr = DV_MapCaptureDevice(lpguidCaptureDevice, &guidCaptureDevice); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapCaptureDevice failed, code: %i", hr); goto error_cleanup; } } // the device guids have been mapped, if required, so save them sinfo.SetCaptureDevice(guidCaptureDevice); sinfo.SetRenderDevice(guidRenderDevice); // get the device descriptions, which also validates the GUIDs on // pre-millennium systems. hr = sinfo.GetDeviceDescriptions(); if (FAILED(hr)) { // error, log it and bail out of the wizard Diagnostics_Write(DVF_ERRORLEVEL, "Error getting device descriptions, code: %i", hr); goto error_cleanup; } // Open the registry key hr = sinfo.OpenRegKey(TRUE); if (FAILED(hr)) { // error, log it and bail out of the wizard Diagnostics_Write(DVF_ERRORLEVEL, "Unable to open reg key, code: %i", hr); hr = DVERR_GENERIC; goto error_cleanup; } fRegKeyOpen = TRUE; if (dwFlags & DVFLAGS_QUERYONLY) { hr = SupervisorQueryAudioSetup(&sinfo); sinfo.CloseRegKey(); DPF_EXIT(); return hr; } g_hResDLLInstance = LoadLibraryA(gc_szResDLLName); if (g_hResDLLInstance == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "Unable to get instance handle to resource dll: %s", gc_szResDLLName); Diagnostics_Write(DVF_ERRORLEVEL, "LoadLibrary error code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // check for other instances of the wizard hr = sinfo.ThereCanBeOnlyOne(); if (FAILED(hr)) { if (hr == DVERR_ALREADYPENDING) { Diagnostics_Write(DVF_ERRORLEVEL, "DirectPlay Voice Setup Wizard already running"); } else { Diagnostics_Write(DVF_ERRORLEVEL, "ThereCanBeOnlyOne failed, hr: %i", hr); } goto error_cleanup; } fMutexOpen = TRUE; // register the peak meter custom control window class hr = pmwc.Register(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "CPeakMeterWndClass::Init failed, code: %i", hr); goto error_cleanup; } fWndClassRegistered = TRUE; // create the wizard header fonts hr = sinfo.CreateTitleFont(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "CreateTitleFont failed"); goto error_cleanup; } fTitleFontCreated = TRUE; hr = sinfo.CreateBoldFont(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "CreateBoldFont failed"); goto error_cleanup; } fBoldFontCreated = TRUE; // prepare the wizard pages PROPSHEETPAGE psp; HPROPSHEETPAGE rghpsp[10]; PROPSHEETHEADER psh; // Welcome page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT; //|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = WelcomeProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOME); rghpsp[0] = CreatePropertySheetPage(&psp); if (rghpsp[0] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Full Duplex Test Page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = FullDuplexProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_FULLDUPLEXTEST); rghpsp[1] = CreatePropertySheetPage(&psp); if (rghpsp[1] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Microphone Test Page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT; //|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = MicTestProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_MICTEST); rghpsp[2] = CreatePropertySheetPage(&psp); if (rghpsp[2] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Microphone Failed Page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = MicTestFailedProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_MICTEST_FAILED); rghpsp[3] = CreatePropertySheetPage(&psp); if (rghpsp[3] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Speaker Test Page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = SpeakerTestProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_SPEAKER_TEST); rghpsp[4] = CreatePropertySheetPage(&psp); if (rghpsp[4] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Wizard Complete Page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = CompleteProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_COMPLETE); rghpsp[5] = CreatePropertySheetPage(&psp); if (rghpsp[5] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // half duplex failed page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = HalfDuplexFailedProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_HALFDUPLEXFAILED); rghpsp[6] = CreatePropertySheetPage(&psp); if (rghpsp[6] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Full duplex failed page ZeroMemory(&psp, sizeof(psp)); // psp.dwSize = sizeof(psp); psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE; psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER; psp.hInstance = g_hResDLLInstance; psp.lParam = (LPARAM) &sinfo; psp.pfnDlgProc = FullDuplexFailedProc; psp.pszTemplate = MAKEINTRESOURCE(IDD_FULLDUPLEXFAILED); rghpsp[7] = CreatePropertySheetPage(&psp); if (rghpsp[7] == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Put it all together... ZeroMemory(&psh, sizeof(psh)); // psh.dwSize = sizeof(psh); psh.dwSize = PROPSHEETHEAD_STRUCT_SIZE; psh.hInstance = g_hResDLLInstance; psh.hwndParent = hwndParent; psh.phpage = rghpsp; psh.dwFlags = PSH_WIZARD; psh.nStartPage = 0; psh.nPages = 8; sinfo.SetError(DV_OK); iRet = (INT) PropertySheet(&psh); if (iRet == -1) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "PropertySheet failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hr = sinfo.DestroyBoldFont(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DestroyBoldFont failed"); goto error_cleanup; } fBoldFontCreated = FALSE; hr = sinfo.DestroyTitleFont(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DestroyTitleFont failed"); goto error_cleanup; } fTitleFontCreated = FALSE; // unregister the peak meter window class hr = pmwc.Unregister(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "CPeakMeterWndClass::Deinit failed, code: %i", hr); goto error_cleanup; } fWndClassRegistered = FALSE; if (!FreeLibrary(g_hResDLLInstance)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "FreeLibrary failed, code: %i", lRet); hr = DVERR_WIN32; goto error_cleanup; } g_hResDLLInstance = NULL; // see if an error occured sinfo.GetError(&hr); if (hr == DV_OK) { // nothing out of the ordinary happened, // so we'll return a cancel if the user // hit cancel, a "user back" if the user exited // the wizard by hitting back from the welcome // page, or the results from the registry otherwise. sinfo.GetUserCancel(&fUserCancel); sinfo.GetUserBack(&fUserBack); if (fUserCancel & fUserBack) { hr = DVERR_USERBACK; } else if(fUserCancel) { hr = DVERR_USERCANCEL; } else { // look in the registry for the test results hr = sinfo.QueryFullDuplex(); // map a run setup result to a total failure if (hr == DVERR_RUNSETUP) { hr = DVERR_SOUNDINITFAILURE; } } } // close the mutex sinfo.CloseMutex(); // close the registry key sinfo.CloseRegKey(); DPF_EXIT(); return hr; error_cleanup: if (fBoldFontCreated == TRUE) { sinfo.DestroyBoldFont(); } fBoldFontCreated = FALSE; if (fTitleFontCreated == TRUE) { sinfo.DestroyTitleFont(); } fTitleFontCreated = FALSE; if (fWndClassRegistered == TRUE) { pmwc.Unregister(); } fWndClassRegistered = FALSE; if (g_hResDLLInstance != NULL) { FreeLibrary(g_hResDLLInstance); } g_hResDLLInstance = NULL; if (fMutexOpen == TRUE) { sinfo.CloseMutex(); } fMutexOpen = FALSE; if (fRegKeyOpen == TRUE) { sinfo.CloseRegKey(); } fRegKeyOpen = FALSE; DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "SupervisorQueryAudioSetup" HRESULT SupervisorQueryAudioSetup(CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr; // will return DV_HALFDUPLEX, DV_FULLDUPLEX, DVERR_SOUNDINITFAILURE or a real error hr = psinfo->QueryFullDuplex(); if (FAILED(hr) && hr != DVERR_SOUNDINITFAILURE && hr != DVERR_RUNSETUP) { Diagnostics_Write(DVF_ERRORLEVEL, "QueryFullDuplex failed, code: %i", hr); } DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CreateTitleFont" HRESULT CSupervisorInfo::CreateTitleFont() { DPF_ENTER(); LONG lRet; HRESULT hr; HFONT hfTitle = NULL; INT iFontSize; LOGFONT lfTitle; HDC hdc = NULL; NONCLIENTMETRICS ncm; DNEnterCriticalSection(&m_csLock); // Set up the font for the titles on the intro and ending pages ZeroMemory(&ncm, sizeof(ncm)); ncm.cbSize = sizeof(ncm); if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "SystemParametersInfo failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Create the intro/end title font lfTitle = ncm.lfMessageFont; lfTitle.lfWeight = FW_BOLD; lstrcpy(lfTitle.lfFaceName, TEXT("MS Shell Dlg")); hdc = GetDC(NULL); //gets the screen DC if (hdc == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDC failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } iFontSize = 12; lfTitle.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * iFontSize / 72; hfTitle = CreateFontIndirect(&lfTitle); if (hfTitle == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateFontIndirect failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } if (ReleaseDC(NULL, hdc) != 1) { hdc = NULL; lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "ReleaseDC failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // save the font m_hfTitle = hfTitle; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: if (hfTitle != NULL) { DeleteObject(hfTitle); } hfTitle = NULL; if (hdc != NULL) { ReleaseDC(NULL, hdc); } hdc = NULL; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::DestroyTitleFont" HRESULT CSupervisorInfo::DestroyTitleFont() { DPF_ENTER(); HFONT hTitleFont; LONG lRet; HRESULT hr; DNEnterCriticalSection(&m_csLock); if (m_hfTitle == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "m_hTitleFont is Null"); hr = DVERR_GENERIC; goto error_cleanup; } if (!DeleteObject(m_hfTitle)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "DeleteObject failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CreateBoldFont" HRESULT CSupervisorInfo::CreateBoldFont() { DPF_ENTER(); LONG lRet; HRESULT hr; HFONT hfBold = NULL; INT iFontSize; LOGFONT lfBold; HDC hdc = NULL; NONCLIENTMETRICS ncm; DNEnterCriticalSection(&m_csLock); // Set up the font for the titles on the intro and ending pages ZeroMemory(&ncm, sizeof(ncm)); ncm.cbSize = sizeof(ncm); if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "SystemParametersInfo failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Create the intro/end title font lfBold = ncm.lfMessageFont; lfBold.lfWeight = FW_BOLD; lstrcpy(lfBold.lfFaceName, TEXT("MS Shell Dlg")); hdc = GetDC(NULL); //gets the screen DC if (hdc == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDC failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } iFontSize = 8; lfBold.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * iFontSize / 72; hfBold = CreateFontIndirect(&lfBold); if (hfBold == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateFontIndirect failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } if (ReleaseDC(NULL, hdc) != 1) { hdc = NULL; lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "ReleaseDC failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // save the font m_hfBold = hfBold; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: if (hdc != NULL) { ReleaseDC(NULL, hdc); } hdc = NULL; if (hfBold != NULL) { DeleteObject(hfBold); } hfBold = NULL; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::DestroyBoldFont" HRESULT CSupervisorInfo::DestroyBoldFont() { DPF_ENTER(); HFONT hTitleFont; LONG lRet; HRESULT hr; DNEnterCriticalSection(&m_csLock); if (m_hfBold == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "m_hTitleFont is Null"); hr = DVERR_GENERIC; goto error_cleanup; } if (!DeleteObject(m_hfBold)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "DeleteObject failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } m_hfBold = NULL; DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::Unmute" HRESULT CSupervisorInfo::Unmute() { DPF_ENTER(); LONG lRet; HRESULT hr; DVCLIENTCONFIG dvcc; DNEnterCriticalSection(&m_csLock); if (m_lpdpvc == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "NULL IDirectPlayVoiceClient"); hr = DVERR_INVALIDPARAM; goto error_cleanup; } dvcc.dwSize = sizeof(dvcc); hr = m_lpdpvc->GetClientConfig(&dvcc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetClientConfig failed, hr: %i", hr); goto error_cleanup; } dvcc.dwFlags &= (~DVCLIENTCONFIG_PLAYBACKMUTE); m_lpdpvc->SetClientConfig(&dvcc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::SetClientConfig failed, hr: %i", hr); goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::Mute" HRESULT CSupervisorInfo::Mute() { DPF_ENTER(); LONG lRet; HRESULT hr; DVCLIENTCONFIG dvcc; DNEnterCriticalSection(&m_csLock); if (m_lpdpvc == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "NULL IDirectPlayVoiceClient"); hr = DVERR_INVALIDPARAM; goto error_cleanup; } dvcc.dwSize = sizeof(dvcc); hr = m_lpdpvc->GetClientConfig(&dvcc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetClientConfig failed, hr: %i", hr); goto error_cleanup; } dvcc.dwFlags |= DVCLIENTCONFIG_PLAYBACKMUTE; m_lpdpvc->SetClientConfig(&dvcc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::SetClientConfig failed, hr: %i", hr); goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::DSEnumCallback" BOOL CALLBACK CSupervisorInfo::DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext) { DNASSERT(lpContext); CSupervisorInfo* psinfo = (CSupervisorInfo*)lpContext; if (lpGuid) { if (psinfo->m_guidRenderDevice == *lpGuid) { // matching guid, copy the description _tcsncpy(psinfo->m_szRenderDeviceDesc, lpcstrDescription, MAX_DEVICE_DESC_LEN-1); // all done, stop enum return FALSE; } } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::DSCEnumCallback" BOOL CALLBACK CSupervisorInfo::DSCEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext) { DNASSERT(lpContext); CSupervisorInfo* psinfo = (CSupervisorInfo*)lpContext; if (lpGuid) { if (psinfo->m_guidCaptureDevice == *lpGuid) { // matching guid, copy the description _tcsncpy(psinfo->m_szCaptureDeviceDesc, lpcstrDescription, MAX_DEVICE_DESC_LEN-1); // all done, stop enum return FALSE; } } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::GetDeviceDescriptions" HRESULT CSupervisorInfo::GetDeviceDescriptions() { DPF_ENTER(); HRESULT hr; TDirectSoundEnumFnc fpDSEnum; TDirectSoundEnumFnc fpDSCEnum; DNEnterCriticalSection(&m_csLock); ZeroMemory(m_szRenderDeviceDesc, MAX_DEVICE_DESC_LEN); ZeroMemory(m_szCaptureDeviceDesc, MAX_DEVICE_DESC_LEN); HINSTANCE hDSound = LoadLibrary(_T("dsound.dll")); if (hDSound == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "Error loading dsound.dll"); hr = DVERR_SOUNDINITFAILURE; goto error_cleanup; } #ifdef UNICODE fpDSEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundEnumerateW"); #else fpDSEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundEnumerateA"); #endif if (fpDSEnum == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "GetProcAddress failed for DirectSoundEnumerateW"); hr = DVERR_SOUNDINITFAILURE; goto error_cleanup; } #ifdef UNICODE fpDSCEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundCaptureEnumerateW"); #else fpDSCEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundCaptureEnumerateA"); #endif if (fpDSCEnum == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "GetProcAddress failed for DirectSoundCaptureEnumerateW"); hr = DVERR_SOUNDINITFAILURE; goto error_cleanup; } hr = fpDSEnum(DSEnumCallback, (LPVOID)this); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DirectSoundEnumerate failed, code: %i, assuming bad guid", hr); hr = DVERR_INVALIDDEVICE; goto error_cleanup; } if (m_szRenderDeviceDesc[0] == NULL) { // the device wasn't found! Diagnostics_Write(DVF_ERRORLEVEL, "Render device not found"); hr = DVERR_INVALIDDEVICE; goto error_cleanup; } hr = fpDSCEnum(DSCEnumCallback, (LPVOID)this); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DirectSoundCaptureEnumerate failed, code: %i, assuming bad guid", hr); hr = DVERR_INVALIDDEVICE; goto error_cleanup; } if (m_szCaptureDeviceDesc[0] == NULL) { // the device wasn't found! Diagnostics_Write(DVF_ERRORLEVEL, "Capture device not found"); hr = DVERR_INVALIDDEVICE; goto error_cleanup; } FreeLibrary( hDSound ); DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return DV_OK; error_cleanup: if( hDSound != NULL ) { FreeLibrary( hDSound ); } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CloseRegKey" HRESULT CSupervisorInfo::CloseRegKey() { DPF_ENTER(); LONG lRet; HRESULT hr; DNEnterCriticalSection(&m_csLock); if (!m_creg.Close()) { Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Close failed"); hr = DVERR_GENERIC; goto error_cleanup; } DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return S_OK; error_cleanup: DNLeaveCriticalSection(&m_csLock); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexTestThreadProc" DWORD WINAPI FullDuplexTestThreadProc(LPVOID lpvParam) { DPF_ENTER(); CSupervisorInfo* lpsinfo; CSupervisorIPC* lpipcSupervisor; LPGUID lpguidRenderDevice; LPGUID lpguidCaptureDevice; HKEY hkDevice; HRESULT hr; LONG lRet; HWND hwnd; lpsinfo = (CSupervisorInfo*)lpvParam; lpsinfo->GetHWNDDialog(&hwnd); hr = RunFullDuplexTest(lpsinfo); // post a message to the wizard so it knows we're done, but // only if this was not a user cancel, since the wizard will // already be waiting on the thread object if (hr != DVERR_USERCANCEL) { if (!PostMessage(hwnd, WM_APP_FULLDUP_TEST_COMPLETE, 0, (LPARAM)hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet); hr = DVERR_GENERIC; } } DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "RunFullDuplexTest" static HRESULT RunFullDuplexTest(CSupervisorInfo* lpsinfo) { DPF_ENTER(); HRESULT hr; HRESULT hrFnc; CSupervisorIPC* lpsipc; lpsinfo->GetIPC(&lpsipc); hr = lpsipc->StartPriorityProcess(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "StartPriorityProcess failed, hr: %i", hr); goto error_cleanup; } hr = lpsipc->StartFullDuplexProcess(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "StartFullDuplexProcess failed, hr: %i", hr); goto error_cleanup; } hrFnc = DoTests(lpsinfo); hr = lpsipc->WaitOnChildren(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "WaitOnChildren failed, code: %i", hr); goto error_cleanup; } DPF_EXIT(); return hrFnc; error_cleanup: // this function is safe to call, even if the child processes have not // been created lpsipc->TerminateChildProcesses(); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::CrashCheckIn" HRESULT CSupervisorInfo::CrashCheckIn() { DPF_ENTER(); LONG lRet; BOOL fRet; DWORD dwRegVal; HRESULT hrFnc; HRESULT hr; HKEY hk; // Each of the following three functions take the critical section, // so there is no need to take it here. // Check each of the test results to see if any tests // crashed. hr = GetHalfDuplex(&dwRegVal); if (!FAILED(hr) && dwRegVal == REGVAL_CRASHED) { // The half duplex test crashed. Diagnostics_Write(DVF_ERRORLEVEL, "Previous half duplex test crashed"); hrFnc = DVERR_PREVIOUSCRASH; goto error_cleanup; } hr = GetFullDuplex(&dwRegVal); if (!FAILED(hr) && dwRegVal == REGVAL_CRASHED) { // The full duplex test crashed. Diagnostics_Write(DVF_ERRORLEVEL, "Previous full duplex test crashed"); hrFnc = DVERR_PREVIOUSCRASH; goto error_cleanup; } hr = GetMicDetected(&dwRegVal); if (!FAILED(hr) && dwRegVal == REGVAL_CRASHED) { // The mic test crashed. Diagnostics_Write(DVF_ERRORLEVEL, "Previous mic test crashed"); hrFnc = DVERR_PREVIOUSCRASH; goto error_cleanup; } DPF_EXIT(); return DV_OK; // error block error_cleanup: DPF_EXIT(); return hrFnc; } #undef DPF_MODNAME #define DPF_MODNAME "DoTests" HRESULT DoTests(CSupervisorInfo* lpsinfo) { DPF_ENTER(); LONG lRet; DWORD dwRet; HANDLE rghEvents[2]; HRESULT hr; HRESULT hrFnc; CSupervisorIPC* lpsipc; lpsinfo->GetIPC(&lpsipc); // wait until the child processes are ready to go... hr = lpsipc->WaitForStartupSignals(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "WaitForStartupSignals failed, hr: %i", hr); goto error_cleanup; } // child processes are all set, tell them what to do // Note: this function has only four expected return codes // DV_FULLDUPLEX - all tests passed // DV_HALFDUPLEX - all half duplex tests passed, full duplex tests failed // DVERR_SOUNDINITFAILURE - half duplex tests failed // DVERR_USERCANCEL - tests canceled by user hrFnc = IssueCommands(lpsinfo); if (FAILED(hrFnc) && hrFnc != DVERR_SOUNDINITFAILURE && hrFnc != DVERR_USERCANCEL) { Diagnostics_Write(DVF_ERRORLEVEL, "IssueCommands failed, hr: %i", hrFnc); hr = hrFnc; goto error_cleanup; } // now tell the child processes to shut down hr = IssueShutdownCommand(lpsipc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "IssueShutdownCommand failed, code: %i", hr); // Note we're not bailing out. We have our test results, so this is // a problem somewhere in the wizard code. Return the result // from the actual test. } DPF_EXIT(); return hrFnc; error_cleanup: // attempt to gracefully shutdown child processes. IssueShutdownCommand(lpsipc); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "IssueCommands" HRESULT IssueCommands(CSupervisorInfo* lpsinfo) { // Note: this function has only four possible return codes // DV_FULLDUPLEX - all tests passed // DV_HALFDUPLEX - all half duplex tests passed, full duplex tests failed // DVERR_SOUNDINITFAILURE - half duplex tests failed // DVERR_USERCANCEL - tests canceled by user DPF_ENTER(); HRESULT hr; DWORD dwIndex1; DWORD dwIndex2; BOOL fAbort = FALSE; BOOL fPassed; // First do a pass testing that we can run in // half duplex without error. // Set the half duplex key to crash state lpsinfo->SetHalfDuplex(REGVAL_CRASHED); dwIndex1 = 0; fPassed = FALSE; while (1) { if (gc_rgwfxPrimaryFormats[dwIndex1].wFormatTag == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nChannels == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nSamplesPerSec == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nAvgBytesPerSec == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nBlockAlign == 0 && gc_rgwfxPrimaryFormats[dwIndex1].wBitsPerSample == 0 && gc_rgwfxPrimaryFormats[dwIndex1].cbSize == 0) { // we've found the last element of the array, break out. fPassed = TRUE; break; } lpsinfo->GetAbortFullDuplex(&fAbort); if (fAbort) { // abort the tests break; } hr = lpsinfo->TestCase(&gc_rgwfxPrimaryFormats[dwIndex1], DVSOUNDCONFIG_HALFDUPLEX|DVSOUNDCONFIG_TESTMODE); if (hr != DV_HALFDUPLEX) { Diagnostics_Write(DVF_ERRORLEVEL, "Half duplex test case not supported hr = 0x%x", hr); break; } ++dwIndex1; // Why is this here? Because DSOUND doesn't like you to open/close quickly. Sleep( 200 ); } if (fAbort) { // The user aborted the tests, make it like they were never run. lpsinfo->SetHalfDuplex(REGVAL_NOTRUN); DPF_EXIT(); return DVERR_USERCANCEL; } // Record the results of the half duplex test in the registry, // and decide what to do next. if (fPassed) { lpsinfo->SetHalfDuplex(REGVAL_PASSED); // continue on with the full duplex test. } else { lpsinfo->SetHalfDuplex(REGVAL_FAILED); // we failed the half duplex test, we're done. DPF_EXIT(); // map all failures at this point to sound problems. return DVERR_SOUNDINITFAILURE; } // Now that we're finished testing in half duplex mode, // we can move on to the full duplex testing. lpsinfo->SetFullDuplex(REGVAL_CRASHED); fPassed = FALSE; dwIndex1 = 0; while (1) { if (gc_rgwfxPrimaryFormats[dwIndex1].wFormatTag == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nChannels == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nSamplesPerSec == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nAvgBytesPerSec == 0 && gc_rgwfxPrimaryFormats[dwIndex1].nBlockAlign == 0 && gc_rgwfxPrimaryFormats[dwIndex1].wBitsPerSample == 0 && gc_rgwfxPrimaryFormats[dwIndex1].cbSize == 0) { // we've found the last element of the array, break out. fPassed = TRUE; break; } lpsinfo->GetAbortFullDuplex(&fAbort); if (fAbort) { // abort the tests break; } hr = lpsinfo->TestCase(&gc_rgwfxPrimaryFormats[dwIndex1], DVSOUNDCONFIG_TESTMODE); if (hr != DV_FULLDUPLEX) { Diagnostics_Write(DVF_ERRORLEVEL, "Full duplex test case not supported. hr = 0x%x", hr); break; } ++dwIndex1; // Why is this here? Because DSOUND doesn't like you to open/close quickly. Sleep( 200 ); } if (fAbort) { // The user aborted the tests, make it like they were never run. lpsinfo->SetFullDuplex(REGVAL_NOTRUN); DPF_EXIT(); return DVERR_USERCANCEL; } // Record the results of the full duplex test in the registry, // and return the appropriate code. if (fPassed) { lpsinfo->SetFullDuplex(REGVAL_PASSED); DPF_EXIT(); return DV_FULLDUPLEX; } else { lpsinfo->SetFullDuplex(REGVAL_FAILED); DPF_EXIT(); return DV_HALFDUPLEX; } } #undef DPF_MODNAME #define DPF_MODNAME "CSupervisorInfo::TestCase" HRESULT CSupervisorInfo::TestCase(const WAVEFORMATEX* lpwfxPrimary, DWORD dwFlags) { DPF_ENTER(); HRESULT hr = DV_OK; HRESULT hrFnc = DV_OK; SFDTestCommand fdtc; // tell the priority process to go ZeroMemory(&fdtc, sizeof(fdtc)); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccPriorityStart; fdtc.fdtu.fdtcPriorityStart.guidRenderDevice = m_guidRenderDevice; fdtc.fdtu.fdtcPriorityStart.wfxRenderFormat = *lpwfxPrimary; fdtc.fdtu.fdtcPriorityStart.wfxSecondaryFormat = gc_wfxSecondaryFormat; fdtc.fdtu.fdtcPriorityStart.hwndWizard = m_hwndWizard; fdtc.fdtu.fdtcPriorityStart.hwndProgress = m_hwndProgress; hr = m_sipc.SendToPriority(&fdtc); if (FAILED(hr)) { DPF_EXIT(); return hr; } // tell the full duplex process to attempt full duplex ZeroMemory(&fdtc, sizeof(fdtc)); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccFullDuplexStart; fdtc.fdtu.fdtcFullDuplexStart.guidRenderDevice = m_guidRenderDevice; fdtc.fdtu.fdtcFullDuplexStart.guidCaptureDevice = m_guidCaptureDevice; fdtc.fdtu.fdtcFullDuplexStart.dwFlags = dwFlags; hrFnc = m_sipc.SendToFullDuplex(&fdtc); if (FAILED(hrFnc)) { // The full duplex process was unable to do it. // tell the priority process to stop and get out. ZeroMemory(&fdtc, sizeof(fdtc)); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccPriorityStop; m_sipc.SendToPriority(&fdtc); DPF_EXIT(); return hrFnc; } // Wait for a half second before we shut it down. // This gives it the time required for the sound system // to detect a lockup if it is going to. Sleep(1000); // The full duplex process was ok, till now. Try to // shut it down. ZeroMemory(&fdtc, sizeof(fdtc)); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccFullDuplexStop; hr = m_sipc.SendToFullDuplex(&fdtc); if (FAILED(hr)) { // It looks like the full duplex wasn't quite up to stuff // after all. Tell the priority process to shut down ZeroMemory(&fdtc, sizeof(fdtc)); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccPriorityStop; m_sipc.SendToPriority(&fdtc); DPF_EXIT(); return hr; } // All is well, up to now, one last hurdle... ZeroMemory(&fdtc, sizeof(fdtc)); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccPriorityStop; hr = m_sipc.SendToPriority(&fdtc); if (FAILED(hr)) { DPF_EXIT(); return hr; } // you have graduated from full duplex class... DPF_EXIT(); return hrFnc; } #undef DPF_MODNAME #define DPF_MODNAME "IssueShutdownCommand" HRESULT IssueShutdownCommand(CSupervisorIPC* lpipcSupervisor) { SFDTestCommand fdtc; HRESULT hr; DPF_EXIT(); fdtc.dwSize = sizeof(fdtc); fdtc.fdtcc = fdtccExit; hr = lpipcSupervisor->SendToFullDuplex(&fdtc); if (FAILED(hr)) { lpipcSupervisor->SendToPriority(&fdtc); DPF_EXIT(); return hr; } hr = lpipcSupervisor->SendToPriority(&fdtc); if (FAILED(hr)) { DPF_EXIT(); return hr; } DPF_EXIT(); return DV_OK; } #undef DPF_MODNAME #define DPF_MODNAME "WelcomeProc" INT_PTR CALLBACK WelcomeProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); BOOL fRet; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : fRet = WelcomeInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : { LPNMHDR lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : // Enable the Next button fRet = WelcomeSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : // Back button clicked fRet = WelcomeBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZNEXT : // Next button clicked fRet = WelcomeNextHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = WelcomeResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } } break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "WelcomeInitDialogHandler" BOOL WelcomeInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndControl; HWND hwndWizard = NULL; LONG lRet; HFONT hfTitle; HICON hIcon; HRESULT hr = DV_OK; HWND hwndParent = NULL; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // It's an intro/end page, so get the title font // from the shared data and use it for the title control hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetTitleFont(&hfTitle); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE); // load the warning icon //hIcon = LoadIcon(NULL, IDI_INFORMATION); //SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); // set the device descriptions SendDlgItemMessage(hDlg, IDC_TEXT_PLAYBACK, WM_SETTEXT, 0, (LPARAM)psinfo->GetRenderDesc()); SendDlgItemMessage(hDlg, IDC_TEXT_RECORDING, WM_SETTEXT, 0, (LPARAM)psinfo->GetCaptureDesc()); // reset the welcome next flag psinfo->ClearWelcomeNext(); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "WelcomeSetActiveHandler" BOOL WelcomeSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndParent; HWND hwndWizard; LONG lRet; DWORD dwFlags; HRESULT hr; // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { // log it, and return, don't know how to terminate the wizard properly // without this handle! lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(NULL); psinfo->SetHWNDOutputPeak(NULL); psinfo->SetHWNDInputVolumeSlider(NULL); psinfo->SetHWNDOutputVolumeSlider(NULL); // set the appropriate wizard buttons as active. psinfo->GetCheckAudioSetupFlags(&dwFlags); if (dwFlags & DVFLAGS_ALLOWBACK) { PropSheet_SetWizButtons(hwndWizard, PSWIZB_NEXT|PSWIZB_BACK); } else { PropSheet_SetWizButtons(hwndWizard, PSWIZB_NEXT); } // reset the user cancel and user back flags psinfo->ClearUserCancel(); psinfo->ClearUserBack(); DPF_EXIT(); return FALSE; // error block error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "WelcomeBackHandler" BOOL WelcomeBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndWizard = NULL; HRESULT hr = DV_OK; LPGUID lpguidCaptureDevice; LPGUID lpguidRenderDevice; HKEY hkey; LONG lRet; DWORD dwErr; DWORD dwRegVal; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); // The back button was hit on the welcome page. Exit the wizard with the appropriate error code. psinfo->SetUserBack(); PropSheet_PressButton(hwndWizard, PSBTN_CANCEL); // no previous crashes (or the user is boldly charging ahead anyway), // so go to the full duplex test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST); DPF_EXIT(); return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "WelcomeNextHandler" BOOL WelcomeNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndWizard = NULL; HRESULT hr = DV_OK; LPGUID lpguidCaptureDevice; LPGUID lpguidRenderDevice; HKEY hkey; LONG lRet; DWORD dwErr; DWORD dwRegVal; HWND hwndParent = NULL; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); // The next button was hit on the welcome page. Do all the basic init tasks. // check for previous crashes hr = psinfo->CrashCheckIn(); if (FAILED(hr)) { if (hr == DVERR_PREVIOUSCRASH) { // the previous test crashed out, display the warning. Diagnostics_Write(DVF_ERRORLEVEL, "DirectPlay Voice Setup Wizard detected previous full duplex test crashed"); int iRet = (INT) DialogBox(g_hResDLLInstance, MAKEINTRESOURCE(IDD_PREVIOUS_CRASH), hDlg, PreviousCrashProc); switch (iRet) { case IDOK: // the previous test crashed, but the user wants to continue // anyway, so move along... Diagnostics_Write(DVF_ERRORLEVEL, "User choosing to ignore previous failure"); break; case IDCANCEL: // the previous test crashed, and the user is wisely choosing // to bail out. Go to either the full duplex failed page, or the // half duplex failed page, depending on the registry state. Diagnostics_Write(DVF_ERRORLEVEL, "User choosing not to run test"); hr = psinfo->GetHalfDuplex(&dwRegVal); if (!FAILED(hr) && dwRegVal == REGVAL_PASSED) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXFAILED); } else { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_HALFDUPLEXFAILED); } return TRUE; break; default: // this is an error Diagnostics_Write(DVF_ERRORLEVEL, "DialogBox failed"); hr = DVERR_GENERIC; goto error_cleanup; } } else { Diagnostics_Write(DVF_ERRORLEVEL, "CrashCheckIn failed, code: %i", hr); goto error_cleanup; } } // no previous crashes (or the user is boldly charging ahead anyway), // so go to the full duplex test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST); DPF_EXIT(); return TRUE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "WelcomeResetHandler" BOOL WelcomeResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr; HWND hwndWizard; // disable all buttons psinfo->GetHWNDWizard(&hwndWizard); PropSheet_SetWizButtons(hwndWizard, 0); psinfo->Cancel(); DPF_EXIT(); return FALSE; } /* #undef DPF_MODNAME #define DPF_MODNAME "AlreadyRunningProc" INT_PTR CALLBACK AlreadyRunningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); HICON hIcon; switch (message) { case WM_INITDIALOG : hIcon = LoadIcon(NULL, IDI_ERROR); SendDlgItemMessage(hDlg, IDC_ICON_ERROR, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; default: break; } break; default: break; } DPF_EXIT(); return FALSE; } */ #undef DPF_MODNAME #define DPF_MODNAME "PreviousCrashProc" INT_PTR CALLBACK PreviousCrashProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); LPNMHDR lpnm; HICON hIcon; Diagnostics_Write(DVF_ERRORLEVEL, "Previous run crashed"); switch (message) { case WM_INITDIALOG : PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC ); hIcon = LoadIcon(NULL, IDI_WARNING); SendDlgItemMessage(hDlg, IDC_ICON_WARNING, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return(TRUE); break; default: break; } break; default: break; } DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexProc" INT_PTR CALLBACK FullDuplexProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); LONG lRet; BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : FullDuplexInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = FullDuplexSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : fRet = FullDuplexBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZNEXT : fRet = FullDuplexNextHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = FullDuplexResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; case WM_APP_FULLDUP_TEST_COMPLETE: fRet = FullDuplexCompleteHandler(hDlg, message, wParam, lParam, psinfo); break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexInitDialogHandler" BOOL FullDuplexInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfBold; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetBoldFont(&hfBold); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfBold, (LPARAM)TRUE); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexSetActiveHandler" BOOL FullDuplexSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndProgress; HWND hwndCancelButton; HANDLE hThread; DWORD dwThreadId; WORD wCount; HRESULT hr = DV_OK; // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // reset all the test registry bits psinfo->SetHalfDuplex(REGVAL_NOTRUN); psinfo->SetFullDuplex(REGVAL_NOTRUN); psinfo->SetMicDetected(REGVAL_NOTRUN); // remember that we've been here, so we'll know to reset the registry // if the user hits cancel from this point forward psinfo->SetWelcomeNext(); // get the progress bar's HWND hwndProgress = GetDlgItem(hDlg, IDC_PROGRESSBAR); if (hwndProgress == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Init the progress bar... // count the number of elements in the primary format array wCount = 0; while (1) { // Increment before we test. This means that if there // are four formats, wCount will equal five after this // loop. ++wCount; if (gc_rgwfxPrimaryFormats[wCount].wFormatTag == 0 && gc_rgwfxPrimaryFormats[wCount].nChannels == 0 && gc_rgwfxPrimaryFormats[wCount].nSamplesPerSec == 0 && gc_rgwfxPrimaryFormats[wCount].nAvgBytesPerSec == 0 && gc_rgwfxPrimaryFormats[wCount].nBlockAlign == 0 && gc_rgwfxPrimaryFormats[wCount].wBitsPerSample == 0 && gc_rgwfxPrimaryFormats[wCount].cbSize == 0) { // we've found the last element of the array, break out. break; } } // set up the progress bar with one segment for each // primary format, times two, since each is tested in // both half and full duplex. SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, wCount*2)); SendMessage(hwndProgress, PBM_SETPOS, 0, 0); SendMessage(hwndProgress, PBM_SETSTEP, 1, 0); // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(hwndProgress); psinfo->SetHWNDInputPeak(NULL); psinfo->SetHWNDOutputPeak(NULL); psinfo->SetHWNDInputVolumeSlider(NULL); psinfo->SetHWNDOutputVolumeSlider(NULL); // clear the abort flag! psinfo->ClearAbortFullDuplex(); // enable the Back button only PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK); // init IPC stuff hr = psinfo->InitIPC(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "Unable to Initialize IPC"); goto error_cleanup; } // Fire up the full duplex test thread hr = psinfo->CreateFullDuplexThread(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "CreateFullDuplexThread failed, code: %i", hr); goto error_cleanup; } DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexNextHandler" BOOL FullDuplexNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); BOOL fPassed; HRESULT hr; HWND hwndWizard; HWND hwndParent = NULL; psinfo->GetFullDuplexResults(&hr); switch (hr) { case DV_HALFDUPLEX: SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXFAILED); Diagnostics_Write(DVF_ERRORLEVEL, "Test resulted in full duplex"); break; case DV_FULLDUPLEX: SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST); Diagnostics_Write(DVF_ERRORLEVEL, "Test resulted in full duplex"); break; case DVERR_SOUNDINITFAILURE: SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_HALFDUPLEXFAILED); Diagnostics_Write(DVF_ERRORLEVEL, "Test encountered unrecoverable error"); break; default: // we should not get any other result Diagnostics_Write(DVF_ERRORLEVEL, "Unexpected full duplex results, hr: %i", hr); goto error_cleanup; } DPF_EXIT(); return TRUE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexBackHandler" BOOL FullDuplexBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr; HWND hwndWizard; HWND hwndParent = NULL; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); // shut down the full duplex test hr = psinfo->CancelFullDuplexTest(); if (FAILED(hr) && hr != DVERR_USERCANCEL) { Diagnostics_Write(DVF_ERRORLEVEL, "CancelFullDuplexTest failed, hr: %i", hr); goto error_cleanup; } // reset the registry to the "test not run" state hr = psinfo->SetHalfDuplex(REGVAL_NOTRUN); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetHalfDuplex failed, code: %i", hr); } hr = psinfo->SetFullDuplex(REGVAL_NOTRUN); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetFullDuplex failed, code: %i", hr); } hr = psinfo->SetMicDetected(REGVAL_NOTRUN); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetMicDetected failed, code: %i", hr); } // go back to the welcome page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_WELCOME); DPF_EXIT(); return TRUE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexCompleteHandler" BOOL FullDuplexCompleteHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndProgress; LONG lRet; HRESULT hr = DV_OK; UINT idsErrorMessage = 0; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); // Disable all the wizard buttons PropSheet_SetWizButtons(hwndWizard, 0); // Get the progress bar window psinfo->GetHWNDProgress(&hwndProgress); // Close the full duplex thread handle and get the test results via the exit code hr = psinfo->WaitForFullDuplexThreadExitCode(); switch(hr) { case DVERR_SOUNDINITFAILURE: case DV_HALFDUPLEX: case DV_FULLDUPLEX: // These are the expected results from the full duplex test thread // this means no strange internal error occured, and it is safe // to move along to the next part of the wizard. // Record the test results psinfo->SetFullDuplexResults(hr); break; case DPNERR_INVALIDDEVICEADDRESS: // This can result from no tcp/ip stack on the machine // we want to dispaly a special error code and then fall // through with the rest of the return codes. idsErrorMessage = IDS_ERROR_NODEVICES; // fall through default: // any other error code is not expected and means we hit // some internal problem. Bail. Diagnostics_Write(DVF_ERRORLEVEL, "Full duplex test thread exited with unexpected error code, hr: %i", hr); psinfo->DeinitIPC(); goto error_cleanup; } // Deinit the IPC stuff hr = psinfo->DeinitIPC(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DeinitIPC failed, code: %i", hr); goto error_cleanup; } // Move the progress bar all the way to the end. SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 1)); SendMessage(hwndProgress, PBM_SETPOS, 1, 0); // enable and press the next button to move // to the next page automatically PropSheet_PressButton(hwndWizard, PSBTN_NEXT); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent, idsErrorMessage); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexResetHandler" BOOL FullDuplexResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestProc" INT_PTR CALLBACK MicTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : fRet = MicTestInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = MicTestSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZNEXT : fRet = MicTestNextHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : fRet = MicTestBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = MicTestResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_RECADVANCED: fRet = MicTestRecAdvancedHandler(hDlg, message, wParam, lParam, psinfo); break; default: break; } break; case WM_APP_LOOPBACK_RUNNING: fRet = MicTestLoopbackRunningHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_APP_RECORDSTART: fRet = MicTestRecordStartHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_APP_RECORDSTOP: fRet = MicTestRecordStopHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_VSCROLL: fRet = MicTestVScrollHandler(hDlg, message, wParam, lParam, psinfo); break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestInitDialogHandler" BOOL MicTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfBold; HWND hwndRecPeak; HWND hwndOutPeak; HWND hwndRecSlider; HWND hwndOutSlider; HWND hwndOutAdvanced; HWND hwndOutGroup; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetBoldFont(&hfBold); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfBold, (LPARAM)TRUE); // Get the peak meter hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER); if (hwndRecPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Init the recording peak meter SendMessage(hwndRecPeak, PM_SETMIN, 0, 0); SendMessage(hwndRecPeak, PM_SETMAX, 0, 99); SendMessage(hwndRecPeak, PM_SETCUR, 0, 0); // Get the recording volume slider hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER); if (hwndRecSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Init the recording volume slider SendMessage(hwndRecSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndRecSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN)); SendMessage(hwndRecSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndRecSlider, TBM_SETTICFREQ, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0); SendMessage(hwndRecSlider, TBM_SETLINESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20); SendMessage(hwndRecSlider, TBM_SETPAGESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5); // Get the playback peak meter hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER); if (hwndOutPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Init the playback peak meter SendMessage(hwndOutPeak, PM_SETMIN, 0, 0); SendMessage(hwndOutPeak, PM_SETMAX, 0, 99); SendMessage(hwndOutPeak, PM_SETCUR, 0, 0); // Get the playback volume slider hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER); if (hwndOutSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Init the playback volume slider SendMessage(hwndOutSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndOutSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN)); SendMessage(hwndOutSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndOutSlider, TBM_SETTICFREQ, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0); SendMessage(hwndOutSlider, TBM_SETLINESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20); SendMessage(hwndOutSlider, TBM_SETPAGESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5); // grey out all the playback volume stuff EnableWindow(hwndOutSlider, FALSE); hwndOutAdvanced = GetDlgItem(hDlg, IDC_OUTADVANCED); if (hwndOutAdvanced == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } EnableWindow(hwndOutAdvanced, FALSE); hwndOutGroup = GetDlgItem(hDlg, IDC_OUTGROUP); if (hwndOutGroup == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } EnableWindow(hwndOutGroup, FALSE); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestSetActiveHandler" BOOL MicTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndRecPeak; HWND hwndOutPeak; HWND hwndRecSlider; HWND hwndOutSlider; HANDLE hThread; HANDLE hEvent; DWORD dwThreadId; HRESULT hr = DV_OK; DWORD dwVolume; // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Set the recording peak meter to zero hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER); if (hwndRecPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndRecPeak, PM_SETCUR, 0, 0); // Get the recording volume control hwnd hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER); if (hwndRecSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Set the slider to max SendMessage(hwndRecSlider, TBM_SETPOS, 1, SendMessage(hwndRecSlider, TBM_GETRANGEMIN, 0, 0)); // Set the playback peak meter to zero hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER); if (hwndOutPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndOutPeak, PM_SETCUR, 0, 0); // Get the playback volume control hwnd hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER); if (hwndOutSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Get the current waveOut volume and set the slider to that position hr = psinfo->GetWaveOutVolume(&dwVolume); if (FAILED(hr)) { // couldn't get the volume - set the slider to top SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMIN, 0, 0)); } else { SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMAX, 0, 0) - dwVolume); } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(hwndRecPeak); psinfo->SetHWNDOutputPeak(hwndOutPeak); psinfo->SetHWNDInputVolumeSlider(hwndRecSlider); psinfo->SetHWNDOutputVolumeSlider(NULL); psinfo->SetLoopbackFlags(0); // clear the voice detected flag psinfo->ClearVoiceDetected(); // clear the mic test reg value psinfo->SetMicDetected(REGVAL_CRASHED); // fire up the loopback test thread hr = psinfo->CreateLoopbackThread(); if (FAILED(hr)) { // error, log it and bail Diagnostics_Write(DVF_ERRORLEVEL, "CreateLoopbackThread failed, code: %i", hr); goto error_cleanup; } // disable the buttons - they will be enabled // when the loopback test is up and running. PropSheet_SetWizButtons(hwndWizard, 0); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestLoopbackRunningHandler" BOOL MicTestLoopbackRunningHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HRESULT hr = DV_OK; HWND hwndRecordSlider; HWND hwndRecordAdvanced; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); // lParam is an HRESULT sent by the loopback test thread hr = (HRESULT)lParam; if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "LoopbackTestThread signaled error, code: %i", hr); goto error_cleanup; } hwndRecordSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER); hwndRecordAdvanced = GetDlgItem( hDlg, IDC_RECADVANCED ); if( hwndRecordSlider != NULL && hwndRecordAdvanced != NULL ) { DWORD dwDeviceFlags; psinfo->GetDeviceFlags( &dwDeviceFlags ); if( dwDeviceFlags & DVSOUNDCONFIG_NORECVOLAVAILABLE ) { EnableWindow( hwndRecordAdvanced, FALSE ); EnableWindow( hwndRecordSlider, FALSE ); } } else { hr = DVERR_GENERIC; DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get record slider window" ); goto error_cleanup; } // clear the voice detected flag psinfo->ClearVoiceDetected(); // enable the next button PropSheet_SetWizButtons(hwndWizard, PSWIZB_NEXT|PSWIZB_BACK); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestRecordStartHandler" BOOL MicTestRecordStartHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); // set the voice detected flag psinfo->SetVoiceDetected(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestRecordStopHandler" BOOL MicTestRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestNextHandler" BOOL MicTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr; HWND hwndWizard; HWND hwndSlider; BOOL fVoiceDetected; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); // If we heard a voice, go to the speaker test page. // Otherwise, go to the mic failed page psinfo->GetVoiceDetected(&fVoiceDetected); if (fVoiceDetected) { // save the current recording slider position hwndSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER); if (hwndSlider == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", GetLastError()); } else { psinfo->SetInputVolumeSliderPos((LONG)SendMessage(hwndSlider, TBM_GETPOS, 0, 0)); } // record the mic test result in the registry psinfo->SetMicDetected(REGVAL_PASSED); // move on to the speaker test. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_SPEAKER_TEST); } else { hr = psinfo->ShutdownLoopbackThread(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr); } // record the mic test result in the registry psinfo->SetMicDetected(REGVAL_FAILED); // go to the mic test failed page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST_FAILED); } DPF_EXIT(); return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestBackHandler" BOOL MicTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr; HWND hwndWizard; BOOL fVoiceDetected; // Get the parent window psinfo->GetHWNDWizard(&hwndWizard); hr = psinfo->ShutdownLoopbackThread(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr); } // shutdown the any volume controls we launched psinfo->CloseWindowsVolumeControl(TRUE); psinfo->CloseWindowsVolumeControl(FALSE); // make it look like the mic test was never run psinfo->SetMicDetected(REGVAL_NOTRUN); // go back to the full duplex test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST); DPF_EXIT(); return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestVScrollHandler" BOOL MicTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndSlider; DWORD dwSliderPos; psinfo->GetHWNDInputVolumeSlider(&hwndSlider); if (hwndSlider == (HWND)lParam) { // the user is moving the input slider dwSliderPos = (DWORD) SendMessage(hwndSlider, TBM_GETPOS, 0, 0); // set the input volume to the user's request psinfo->SetRecordVolume(AmpFactorToDB(DBToAmpFactor(DSBVOLUME_MAX)-dwSliderPos)); } DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestRecAdvancedHandler" BOOL MicTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed"); DPF_EXIT(); return FALSE; } psinfo->LaunchWindowsVolumeControl(hwndWizard, TRUE); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "LoopbackTestThreadProc" DWORD WINAPI LoopbackTestThreadProc(LPVOID lpvParam) { DPF_ENTER(); CSupervisorInfo* psinfo; HRESULT hr; LONG lRet; HWND hwnd; LPDIRECTPLAYVOICESERVER lpdpvs; LPDIRECTPLAYVOICECLIENT lpdpvc; PDIRECTPLAY8SERVER lpdp8; DWORD dwRet; HANDLE hEvent; DWORD dwWaveOutId; DWORD dwWaveInId; HWND hwndWizard; GUID guidCaptureDevice; GUID guidRenderDevice; DWORD dwFlags; DWORD dwSize; PDVSOUNDDEVICECONFIG pdvsdc = NULL; PBYTE pdvsdcBuffer = NULL; BOOL fLoopbackStarted = FALSE; psinfo = (CSupervisorInfo*)lpvParam; psinfo->GetHWNDDialog(&hwnd); psinfo->GetHWNDWizard(&hwndWizard); psinfo->GetCaptureDevice(&guidCaptureDevice); psinfo->GetRenderDevice(&guidRenderDevice); psinfo->GetLoopbackFlags(&dwFlags); lpdpvs = NULL; lpdpvc = NULL; lpdp8 = NULL; // new thread, init COM hr = COM_CoInitialize(NULL); if( FAILED( hr ) ) { Diagnostics_Write(DVF_ERRORLEVEL, "COM_CoInitialize failed, code: %i", hr); if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet); } goto error_cleanup; } hr = StartDirectPlay( &lpdp8 ); if( FAILED( hr ) ) { Diagnostics_Write(DVF_ERRORLEVEL, "StartDirectPlay failed, code: 0x%x", hr); goto error_cleanup; } hr = StartLoopback( &lpdpvs, &lpdpvc, &lpdp8, (LPVOID)psinfo, hwndWizard, guidCaptureDevice, guidRenderDevice, dwFlags); if (FAILED(hr) ) { Diagnostics_Write(DVF_ERRORLEVEL, "StartLoopback failed, code: %i", hr); if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet); } goto error_cleanup; } psinfo->SetLoopbackRunning( TRUE ); if( !(dwFlags & DVSOUNDCONFIG_HALFDUPLEX) && hr == DV_HALFDUPLEX ) { Diagnostics_Write(DVF_ERRORLEVEL, "StartLoopback failed with half duplex when expecting full duplex", hr); if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet); } goto error_cleanup; } // save the voice client interface for the other threads to play with psinfo->SetDPVC(lpdpvc); dwSize = 0; hr = lpdpvc->GetSoundDeviceConfig(pdvsdc, &dwSize); if( hr != DVERR_BUFFERTOOSMALL ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "GetSoundDeviceConfig failed, hr: %i", hr ); if (!FAILED(hr)) { // map success codes to a generic failure, since we // did not expect success hr = DVERR_GENERIC; } goto error_cleanup; } pdvsdcBuffer = new BYTE[dwSize]; if( pdvsdcBuffer == NULL ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory alloc failure" ); hr = DVERR_OUTOFMEMORY; goto error_cleanup; } pdvsdc = (PDVSOUNDDEVICECONFIG) pdvsdcBuffer; pdvsdc->dwSize = sizeof( DVSOUNDDEVICECONFIG ); hr = lpdpvc->GetSoundDeviceConfig(pdvsdc, &dwSize); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "GetSoundDeviceConfig failed, hr: %i", hr); goto error_cleanup; } hr = DV_MapGUIDToWaveID(FALSE, pdvsdc->guidPlaybackDevice, &dwWaveOutId); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapGUIDToWaveID failed, hr: %i", hr); goto error_cleanup; } hr = psinfo->SetWaveOutId(dwWaveOutId); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetWaveOutId failed, hr: %i", hr); goto error_cleanup; } hr = DV_MapGUIDToWaveID(TRUE, pdvsdc->guidCaptureDevice, &dwWaveInId); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapGUIDToWaveID failed, hr: %i", hr); goto error_cleanup; } psinfo->SetWaveInId(dwWaveInId); psinfo->SetDeviceFlags( pdvsdc->dwFlags ); // inform the app that loopback is up and running. hr = DV_OK; // Also send along the flags from GetSoundDeviceConfig if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr)) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet); goto error_cleanup; } // wait on the shutdown event hr = psinfo->WaitForLoopbackShutdownEvent(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "WaitForLoopbackShutdown failed, code: %i", hr); goto error_cleanup; } psinfo->SetLoopbackRunning( FALSE); delete [] pdvsdcBuffer; pdvsdcBuffer = NULL; // Null out the interface pointer in sinfo psinfo->SetDPVC(NULL); // shutdown the loopback test hr = StopLoopback(lpdpvs, lpdpvc, lpdp8); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "StopLoopback failed, code: %i", hr); goto error_cleanup; } hr = StopDirectPlay( lpdp8 ); lpdp8 = NULL; if( FAILED( hr ) ) { Diagnostics_Write(DVF_ERRORLEVEL, "StopDirectPlay failed, code: %i", hr); goto error_cleanup; } // Signal the loopback thread exit event psinfo->SignalLoopbackThreadDone(); COM_CoUninitialize(); DPF_EXIT(); return DV_OK; error_cleanup: if (pdvsdcBuffer != NULL) { delete [] pdvsdcBuffer; } if (fLoopbackStarted) { StopLoopback(lpdpvs, lpdpvc, lpdp8); } if( lpdp8 ) { StopDirectPlay( lpdp8 ); } psinfo->SetLoopbackRunning( FALSE); psinfo->SignalLoopbackThreadDone(); COM_CoUninitialize(); DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestResetHandler" BOOL MicTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "CompleteProc" INT_PTR CALLBACK CompleteProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : fRet = CompleteInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = CompleteSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZFINISH : fRet = CompleteFinishHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = CompleteResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "CompleteInitDialogHandler" BOOL CompleteInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfTitle; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetTitleFont(&hfTitle); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "CompleteSetActiveHandler" BOOL CompleteSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard; HWND hwndParent = NULL; HANDLE hEvent; HRESULT hr; // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { // log it, and return, don't know how to terminate the wizard properly // without this handle! lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(NULL); psinfo->SetHWNDOutputPeak(NULL); psinfo->SetHWNDInputVolumeSlider(NULL); psinfo->SetHWNDOutputVolumeSlider(NULL); PropSheet_SetWizButtons(hwndWizard, PSWIZB_FINISH); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "CompleteFinishHandler" BOOL CompleteFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); psinfo->Finish(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "CompleteResetHandler" BOOL CompleteResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedProc" INT_PTR CALLBACK MicTestFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); LONG lRet; BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : MicTestFailedInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = MicTestFailedSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : fRet = MicTestFailedBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = MicTestFailedResetHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZFINISH : fRet = MicTestFailedFinishHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedInitDialogHandler" BOOL MicTestFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfTitle; HICON hIcon; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetTitleFont(&hfTitle); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE); // load the warning icon hIcon = LoadIcon(NULL, IDI_WARNING); SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); DPF_EXIT(); return FALSE; // error block error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedSetActiveHandler" BOOL MicTestFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard; HWND hwndParent = NULL; HWND hwndPeak; HANDLE hEvent; HRESULT hr; PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC ); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { // log it, and return, don't know how to terminate the wizard properly // without this handle! lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(NULL); psinfo->SetHWNDOutputPeak(NULL); psinfo->SetHWNDInputVolumeSlider(NULL); psinfo->SetHWNDOutputVolumeSlider(NULL); // enable the finish and back buttons PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_FINISH); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedRecordStopHandler" BOOL MicTestFailedRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedBackHandler" BOOL MicTestFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); // go back to the mic test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST); DPF_EXIT(); return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedResetHandler" BOOL MicTestFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "MicTestFailedFinishHandler" BOOL MicTestFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); psinfo->Finish(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestProc" INT_PTR CALLBACK SpeakerTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); LONG lRet; BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : SpeakerTestInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = SpeakerTestSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZNEXT : fRet = SpeakerTestNextHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : fRet = SpeakerTestBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = SpeakerTestResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_RECADVANCED: fRet = SpeakerTestRecAdvancedHandler(hDlg, message, wParam, lParam, psinfo); break; case IDC_OUTADVANCED: fRet = SpeakerTestOutAdvancedHandler(hDlg, message, wParam, lParam, psinfo); break; default: break; } break; case WM_VSCROLL: fRet = SpeakerTestVScrollHandler(hDlg, message, wParam, lParam, psinfo); break; default: break; } DPF_ENTER(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestInitDialogHandler" BOOL SpeakerTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfBold; HWND hwndRecPeak; HWND hwndOutPeak; HWND hwndRecSlider; HWND hwndOutSlider; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetBoldFont(&hfBold); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfBold, (LPARAM)TRUE); // Init the recording peak meter hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER); if (hwndRecPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndRecPeak, PM_SETMIN, 0, 0); SendMessage(hwndRecPeak, PM_SETMAX, 0, 99); SendMessage(hwndRecPeak, PM_SETCUR, 0, 0); // Init the recording volume slider hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER); if (hwndRecSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndRecSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndRecSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN)); SendMessage(hwndRecSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndRecSlider, TBM_SETTICFREQ, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0); SendMessage(hwndRecSlider, TBM_SETLINESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20); SendMessage(hwndRecSlider, TBM_SETPAGESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5); // Init the playback peak meter hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER); if (hwndOutPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndOutPeak, PM_SETMIN, 0, 0); SendMessage(hwndOutPeak, PM_SETMAX, 0, 99); SendMessage(hwndOutPeak, PM_SETCUR, 0, 0); // Init the playback volume slider hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER); if (hwndOutSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndOutSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndOutSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN)); SendMessage(hwndOutSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX)); SendMessage(hwndOutSlider, TBM_SETTICFREQ, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0); SendMessage(hwndOutSlider, TBM_SETLINESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20); SendMessage(hwndOutSlider, TBM_SETPAGESIZE, 0, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestSetActiveHandler" BOOL SpeakerTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndRecPeak; HWND hwndOutPeak; HWND hwndRecSlider; HWND hwndOutSlider; HANDLE hEvent; HRESULT hr = DV_OK; DWORD dwVolume; HWND hwndRecAdvanced; // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Reset the recording peak meter hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER); if (hwndRecPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndRecPeak, PM_SETCUR, 0, 0); // set the recording volume slider to match // the recording volume slider from the mic // test page. hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER); if (hwndRecSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndRecAdvanced = GetDlgItem( hDlg, IDC_RECADVANCED ); if (hwndRecAdvanced == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = lRet; goto error_cleanup; } DWORD dwDeviceFlags; psinfo->GetDeviceFlags( &dwDeviceFlags ); if( dwDeviceFlags & DVSOUNDCONFIG_NORECVOLAVAILABLE ) { EnableWindow( hwndRecSlider, FALSE ); EnableWindow( hwndRecAdvanced, FALSE ); } LONG lPos; psinfo->GetInputVolumeSliderPos(&lPos); SendMessage(hwndRecSlider, TBM_SETPOS, 1, lPos); // Reset the playback peak meter hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER); if (hwndOutPeak == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } SendMessage(hwndOutPeak, PM_SETCUR, 0, 0); // Grey out the playback volume slider - until we come back // to fix it hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER); if (hwndOutSlider == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // Get the current waveOut volume and set the slider to that position hr = psinfo->GetWaveOutVolume(&dwVolume); if (FAILED(hr)) { // couldn't get the volume - set the slider to top SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMIN, 0, 0)); // disable the slider EnableWindow(hwndOutSlider, FALSE); } else { SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMAX, 0, 0) - dwVolume); } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(hwndRecPeak); psinfo->SetHWNDOutputPeak(hwndOutPeak); psinfo->SetHWNDInputVolumeSlider(hwndRecSlider); psinfo->SetHWNDOutputVolumeSlider(hwndOutSlider); // unmute the output hr = psinfo->Unmute(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "Unmute failed, code: %i", hr); goto error_cleanup; } // enable the next button PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_NEXT); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestNextHandler" BOOL SpeakerTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr = DV_OK; HWND hwndWizard = NULL; HWND hwndParent = NULL; // get the parent window psinfo->GetHWNDWizard(&hwndWizard); // shutdown the loopback test hr = psinfo->ShutdownLoopbackThread(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr); goto error_cleanup; } // close any volume controls that are open. psinfo->CloseWindowsVolumeControl(TRUE); psinfo->CloseWindowsVolumeControl(FALSE); // the next page is the completion page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_COMPLETE); DPF_EXIT(); return TRUE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestBackHandler" BOOL SpeakerTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HRESULT hr = DV_OK; HWND hwndWizard = NULL; HWND hwndParent = NULL; // get the parent window psinfo->GetHWNDWizard(&hwndWizard); // shutdown the loopback test, so the mic test // page can start fresh. hr = psinfo->ShutdownLoopbackThread(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, hr: %i", hr); goto error_cleanup; } // close the output volume control, if showing psinfo->CloseWindowsVolumeControl(FALSE); // go back to the mic test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST); DPF_EXIT(); return TRUE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestResetHandler" BOOL SpeakerTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestVScrollHandler" BOOL SpeakerTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndSlider; DWORD dwSliderPos; psinfo->GetHWNDInputVolumeSlider(&hwndSlider); if (hwndSlider == (HWND)lParam) { // the user is moving the input slider dwSliderPos = (DWORD)SendMessage(hwndSlider, TBM_GETPOS, 0, 0); // set the input volume to the user's request psinfo->SetRecordVolume(AmpFactorToDB(DBToAmpFactor(DSBVOLUME_MAX)-dwSliderPos)); } psinfo->GetHWNDOutputVolumeSlider(&hwndSlider); if (hwndSlider == (HWND)lParam) { // the user is moving the output slider dwSliderPos = (DWORD) SendMessage(hwndSlider, TBM_GETPOS, 0, 0); // set the output volume psinfo->SetWaveOutVolume( ((DWORD) SendMessage(hwndSlider, TBM_GETRANGEMAX, 0, 0)) - dwSliderPos); } DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestRecAdvancedHandler" BOOL SpeakerTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed"); DPF_EXIT(); return FALSE; } psinfo->LaunchWindowsVolumeControl(hwndWizard, TRUE); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "SpeakerTestOutAdvancedHandler" BOOL SpeakerTestOutAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); HWND hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed"); DPF_EXIT(); return FALSE; } psinfo->LaunchWindowsVolumeControl(hwndWizard, FALSE); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexFailedProc" INT_PTR CALLBACK FullDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : fRet = FullDuplexFailedInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = FullDuplexFailedSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZFINISH : fRet = FullDuplexFailedFinishHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : fRet = FullDuplexFailedBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = FullDuplexFailedResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexFailedInitDialogHandler" BOOL FullDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfTitle; HICON hIcon; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetTitleFont(&hfTitle); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE); // load the warning icon hIcon = LoadIcon(NULL, IDI_WARNING); SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexFailedSetActiveHandler" BOOL FullDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard; HWND hwndParent = NULL; HANDLE hEvent; HRESULT hr; PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC ); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(NULL); psinfo->SetHWNDOutputPeak(NULL); psinfo->SetHWNDInputVolumeSlider(NULL); psinfo->SetHWNDOutputVolumeSlider(NULL); PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_FINISH); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexFailedFinishHandler" BOOL FullDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); psinfo->Finish(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexFailedResetHandler" BOOL FullDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "FullDuplexFailedBackHandler" BOOL FullDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); // go back to the full duplex test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST); DPF_EXIT(); return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "HalfDuplexFailedProc" INT_PTR CALLBACK HalfDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); BOOL fRet; LPNMHDR lpnm; CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA); fRet = FALSE; switch (message) { case WM_INITDIALOG : fRet = HalfDuplexFailedInitDialogHandler(hDlg, message, wParam, lParam, psinfo); break; case WM_NOTIFY : lpnm = (LPNMHDR) lParam; switch (lpnm->code) { case PSN_SETACTIVE : fRet = HalfDuplexFailedSetActiveHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZFINISH : fRet = HalfDuplexFailedFinishHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_WIZBACK : fRet = HalfDuplexFailedBackHandler(hDlg, message, wParam, lParam, psinfo); break; case PSN_RESET : fRet = HalfDuplexFailedResetHandler(hDlg, message, wParam, lParam, psinfo); break; default : break; } break; default: break; } DPF_EXIT(); return fRet; } #undef DPF_MODNAME #define DPF_MODNAME "HalfDuplexFailedInitDialogHandler" BOOL HalfDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard = NULL; HWND hwndParent = NULL; HWND hwndControl; HFONT hfTitle; HICON hIcon; HRESULT hr = DV_OK; // Get the shared data from PROPSHEETPAGE lParam value // and load it into GWLP_USERDATA psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } hwndControl = GetDlgItem(hDlg, IDC_TITLE); if (hwndControl == NULL) { // error, log it and bail lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } psinfo->GetTitleFont(&hfTitle); (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE); // load the warning icon hIcon = LoadIcon(NULL, IDI_WARNING); SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "HalfDuplexFailedSetActiveHandler" BOOL HalfDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); LONG lRet; HWND hwndWizard; HWND hwndParent = NULL; HANDLE hEvent; HRESULT hr; PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC ); // Get the parent window hwndWizard = GetParent(hDlg); if (hwndWizard == NULL) { lRet = GetLastError(); Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // set the HWNDs psinfo->SetHWNDWizard(hwndWizard); psinfo->SetHWNDDialog(hDlg); psinfo->SetHWNDProgress(NULL); psinfo->SetHWNDInputPeak(NULL); psinfo->SetHWNDOutputPeak(NULL); psinfo->SetHWNDInputVolumeSlider(NULL); psinfo->SetHWNDOutputVolumeSlider(NULL); PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_FINISH); DPF_EXIT(); return FALSE; error_cleanup: psinfo->GetHWNDParent(&hwndParent); DV_DisplayErrorBox(hr, hwndParent); psinfo->SetError(hr); psinfo->Abort(hDlg, hr); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "HalfDuplexFailedFinishHandler" BOOL HalfDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); psinfo->Finish(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "HalfDuplexFailedResetHandler" BOOL HalfDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); DPF_EXIT(); return FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "HalfDuplexFailedBackHandler" BOOL HalfDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo) { DPF_ENTER(); // go back to the full duplex test page SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST); DPF_EXIT(); return TRUE; }