Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6970 lines
178 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: supervis.cpp
  6. * Content: Implements a process that oversees the full duplex
  7. * testing proceedure, watching for nasty conditions in
  8. * the two child processes that are used to implement the
  9. * actual tests. This is required because on some older
  10. * VXD drivers, attempting full duplex can hang the process
  11. * or even (grumble) lock the whole system.
  12. * History:
  13. * Date By Reason
  14. * ============
  15. * 08/19/99 pnewson created
  16. * 10/27/99 pnewson change guid members from pointers to structs
  17. * 10/28/99 pnewson Bug #114176 updated DVSOUNDDEVICECONFIG struct
  18. * 11/04/99 pnewson Bug #115279 - fixed cancel processing
  19. * - fixed crash detection
  20. * - fixed multiple instance detection
  21. * - added HWND to check audio setup
  22. * - automatically advance after full duplex test
  23. * 11/30/99 pnewson parameter validation and default device mapping
  24. * 12/16/99 rodtoll Bug #119584 - Error code cleanup (Renamed runsetup error)
  25. * 01/21/2000 pnewson Update for UI revisions
  26. * 01/23/2000 pnewson Improvded feedback for fatal errors (millen bug 114508)
  27. * 01/24/2000 pnewson Prefix detected bug fix
  28. * 01/25/2000 pnewson Added support for DVFLAGS_WAVEIDS
  29. * 01/27/2000 rodtoll Updated with API changes
  30. * 02/08/2000 rodtoll Bug #131496 - Selecting DVTHRESHOLD_DEFAULT results in voice
  31. * never being detected
  32. * 03/03/2000 rodtoll Updated to handle alternative gamevoice build.
  33. * 03/23/2000 rodtoll Win64 updates
  34. * 04/04/2000 pnewson Added support for DVFLAGS_ALLOWBACK
  35. * Removed "Already Running" dialog box
  36. * 04/19/2000 rodtoll Bug #31106 - Grey out recording sliders when no vol control avail
  37. * 04/19/2000 pnewson Error handling cleanup
  38. * Clicking Volume button brings volume window to foreground
  39. * 04/21/2000 rodtoll Bug #32889 - Does not run on Win2k on non-admin account
  40. * Bug #32952 Does not run on Windows 95 w/o IE4 installed
  41. * 05/03/2000 pnewson Bug #33878 - Wizard locks up when clicking Next/Cancel during speaker test
  42. * 05/17/2000 rodtoll Bug #34045 - Parameter validation error while running TestNet.
  43. * rodtoll Bug #34764 - Verifies capture device before render device
  44. * 06/28/2000 rodtoll Prefix Bug #38022
  45. * 07/12/2000 rodtoll Bug #31468 - Add diagnostic spew to logfile to show what is failing the HW Wizard
  46. * 07/31/2000 rodtoll Bug #39590 - SB16 class soundcards are passing when they should fail
  47. * Half duplex code was being ignored in mic test portion.
  48. * 08/06/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  49. * 08/28/2000 masonb Voice Merge: Changed ccomutil.h to ccomutil.h
  50. * 08/31/2000 rodtoll Bug #43804 - DVOICE: dwSensitivity structure member is confusing - should be dwThreshold
  51. * 11/29/2000 rodtoll Bug #48348 - DPVOICE: Modify wizard to make use of DirectPlay8 as the transport.
  52. * 02/04/2001 simonpow Bug #354859 - Fixes for PREfast spotted problems (Unitialised variables)
  53. * 02/25/2002 rodtoll WINBUG #550085 - SECURITY: DPVOICE: Non-validated registry reads
  54. * - Adding validation for registry reads from HKCU for volume settings etc.
  55. * 03/01/2002 simonpow Bug #55054 Fixed CreateProcess call to specify both app
  56. * name and command line
  57. * 04/24/2002 simonpow Bug #569866 Added release for critical section in Abort fn
  58. ***************************************************************************/
  59. #include "dxvtlibpch.h"
  60. #ifndef WIN95
  61. #define PROPSHEETPAGE_STRUCT_SIZE sizeof( PROPSHEETPAGE )
  62. #define PROPSHEETHEAD_STRUCT_SIZE sizeof( PROPSHEETHEADER )
  63. #else
  64. #define PROPSHEETPAGE_STRUCT_SIZE PROPSHEETPAGE_V1_SIZE
  65. #define PROPSHEETHEAD_STRUCT_SIZE PROPSHEETHEADER_V1_SIZE
  66. #endif
  67. #undef DPF_SUBCOMP
  68. #define DPF_SUBCOMP DN_SUBCOMP_VOICE
  69. // logical defines for registry values
  70. #define REGVAL_NOTRUN 0
  71. #define REGVAL_CRASHED 1
  72. #define REGVAL_FAILED 2
  73. #define REGVAL_PASSED 3
  74. // Anything above this value is invalid
  75. #define REGVAL_MAXVALID REGVAL_PASSED
  76. // local typedefs
  77. typedef HRESULT (WINAPI *TDirectSoundEnumFnc)(LPDSENUMCALLBACK, LPVOID);
  78. // local static functions
  79. static HRESULT SupervisorQueryAudioSetup(CSupervisorInfo* psinfo);
  80. static HRESULT RunFullDuplexTest(CSupervisorInfo* lpsinfo);
  81. static HRESULT DoTests(CSupervisorInfo* lpsinfo);
  82. static HRESULT IssueCommands(CSupervisorInfo* lpsinfo);
  83. static HRESULT IssueShutdownCommand(CSupervisorIPC* lpipcSupervisor);
  84. // callback functions
  85. INT_PTR CALLBACK WelcomeProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  86. INT_PTR CALLBACK AlreadyRunningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  87. INT_PTR CALLBACK PreviousCrashProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  88. INT_PTR CALLBACK FullDuplexProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  89. INT_PTR CALLBACK MicTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  90. INT_PTR CALLBACK MicTestFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  91. INT_PTR CALLBACK SpeakerTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  92. INT_PTR CALLBACK CompleteProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  93. INT_PTR CALLBACK FullDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  94. INT_PTR CALLBACK HalfDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  95. // Thread functions
  96. DWORD WINAPI FullDuplexTestThreadProc(LPVOID lpvParam);
  97. DWORD WINAPI LoopbackTestThreadProc(LPVOID lpvParam);
  98. // Message handlers
  99. BOOL WelcomeInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  100. BOOL WelcomeSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  101. BOOL WelcomeBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  102. BOOL WelcomeNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  103. BOOL WelcomeResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  104. BOOL FullDuplexInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  105. BOOL FullDuplexSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  106. BOOL FullDuplexBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  107. BOOL FullDuplexNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  108. BOOL FullDuplexCompleteHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  109. BOOL FullDuplexResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  110. BOOL MicTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  111. BOOL MicTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  112. BOOL MicTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  113. BOOL MicTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  114. BOOL MicTestLoopbackRunningHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  115. BOOL MicTestRecordStartHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  116. BOOL MicTestRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  117. BOOL MicTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  118. BOOL MicTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  119. BOOL MicTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  120. BOOL MicTestFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  121. BOOL MicTestFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  122. BOOL MicTestFailedRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  123. BOOL MicTestFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  124. BOOL MicTestFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  125. BOOL MicTestFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  126. BOOL SpeakerTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  127. BOOL SpeakerTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  128. BOOL SpeakerTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  129. BOOL SpeakerTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  130. BOOL SpeakerTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  131. BOOL SpeakerTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  132. BOOL SpeakerTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  133. BOOL SpeakerTestOutAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  134. BOOL CompleteInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  135. BOOL CompleteSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  136. BOOL CompleteLoopbackEndedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  137. BOOL CompleteFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  138. BOOL CompleteResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  139. BOOL FullDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  140. BOOL FullDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  141. BOOL FullDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  142. BOOL FullDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  143. BOOL FullDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  144. BOOL HalfDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  145. BOOL HalfDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  146. BOOL HalfDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  147. BOOL HalfDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  148. BOOL HalfDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo);
  149. // globals
  150. HINSTANCE g_hResDLLInstance;
  151. #undef DPF_MODNAME
  152. #define DPF_MODNAME "CSupervisorInfo::CSupervisorInfo"
  153. CSupervisorInfo::CSupervisorInfo()
  154. : m_hfTitle(NULL)
  155. , m_guidCaptureDevice(GUID_NULL)
  156. , m_guidRenderDevice(GUID_NULL)
  157. , m_hFullDuplexThread(NULL)
  158. , m_hLoopbackThreadExitEvent(NULL)
  159. , m_fAbortFullDuplex(FALSE)
  160. , m_hLoopbackThread(NULL)
  161. , m_hLoopbackShutdownEvent(NULL)
  162. , m_fVoiceDetected(FALSE)
  163. , m_hwndWizard(NULL)
  164. , m_hwndDialog(NULL)
  165. , m_hwndProgress(NULL)
  166. , m_hwndInputPeak(NULL)
  167. , m_hwndOutputPeak(NULL)
  168. , m_hwndInputVolumeSlider(NULL)
  169. , m_hwndOutputVolumeSlider(NULL)
  170. , m_lpdpvc(NULL)
  171. , m_hMutex(NULL)
  172. , m_uiWaveInDeviceId(0)
  173. , m_uiWaveOutDeviceId(0)
  174. , m_dwDeviceFlags(0)
  175. , m_fLoopbackRunning(FALSE)
  176. , m_fCritSecInited(FALSE)
  177. {
  178. DPF_ENTER();
  179. ZeroMemory(&m_piSndVol32Record, sizeof(PROCESS_INFORMATION));
  180. ZeroMemory(&m_piSndVol32Playback, sizeof(PROCESS_INFORMATION));
  181. ZeroMemory(&m_woCaps, sizeof(WAVEOUTCAPS));
  182. DPF_EXIT();
  183. return;
  184. }
  185. #undef DPF_MODNAME
  186. #define DPF_MODNAME "CSupervisorInfo::~CSupervisorInfo"
  187. CSupervisorInfo::~CSupervisorInfo()
  188. {
  189. if (m_fCritSecInited)
  190. {
  191. DNDeleteCriticalSection(&m_csLock);
  192. }
  193. }
  194. // this structure is only used by the next two functions, hence
  195. // it is declared here for convenince.
  196. struct SMoveWindowEnumProcParam
  197. {
  198. PROCESS_INFORMATION* lppi;
  199. int x;
  200. int y;
  201. BOOL fMoved;
  202. };
  203. struct SBringToForegroundEnumProcParam
  204. {
  205. PROCESS_INFORMATION* lppi;
  206. BOOL fFound;
  207. };
  208. #undef DPF_MODNAME
  209. #define DPF_MODNAME "BringToForegroundWindowProc"
  210. BOOL CALLBACK BringToForegroundWindowProc(HWND hwnd, LPARAM lParam)
  211. {
  212. SBringToForegroundEnumProcParam* param;
  213. param = (SBringToForegroundEnumProcParam*)lParam;
  214. DPFX(DPFPREP, DVF_INFOLEVEL, "looking for main window for pid: %i", param->lppi->dwProcessId);
  215. DWORD dwProcessId;
  216. GetWindowThreadProcessId(hwnd, &dwProcessId);
  217. DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId);
  218. if (dwProcessId == param->lppi->dwProcessId)
  219. {
  220. TCHAR rgtchClassName[64];
  221. GetClassName(hwnd, rgtchClassName, 64);
  222. if (_tcsnicmp(rgtchClassName, _T("Volume Control"), 64) == 0)
  223. {
  224. if (!SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE))
  225. {
  226. Diagnostics_Write(DVF_ERRORLEVEL, "SetWindowPos failed, code: 0x%x", GetLastError());
  227. }
  228. else
  229. {
  230. param->fFound = TRUE;
  231. }
  232. }
  233. return FALSE;
  234. }
  235. return TRUE;
  236. }
  237. #undef DPF_MODNAME
  238. #define DPF_MODNAME "BringToForegroundWindowEnumProc"
  239. BOOL CALLBACK BringToForegroundWindowEnumProc(HWND hwnd, LPARAM lParam)
  240. {
  241. SMoveWindowEnumProcParam* param;
  242. param = (SMoveWindowEnumProcParam*)lParam;
  243. DPFX(DPFPREP, DVF_INFOLEVEL, "looking for main window for pid: 0x%x", param->lppi->dwProcessId);
  244. DWORD dwProcessId;
  245. GetWindowThreadProcessId(hwnd, &dwProcessId);
  246. DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId);
  247. if (dwProcessId == param->lppi->dwProcessId)
  248. {
  249. TCHAR rgtchClassName[64];
  250. GetClassName(hwnd, rgtchClassName, 64);
  251. if (_tcsnicmp(rgtchClassName, _T("Volume Control"), 64) == 0)
  252. {
  253. if (!SetForegroundWindow(hwnd))
  254. {
  255. Diagnostics_Write(DVF_ERRORLEVEL, "SetForegroundWindow failed, code: 0x%x", GetLastError());
  256. }
  257. }
  258. return FALSE;
  259. }
  260. return TRUE;
  261. }
  262. #undef DPF_MODNAME
  263. #define DPF_MODNAME "MoveWindowEnumProc"
  264. BOOL CALLBACK MoveWindowEnumProc(HWND hwnd, LPARAM lParam)
  265. {
  266. SMoveWindowEnumProcParam* param;
  267. param = (SMoveWindowEnumProcParam*)lParam;
  268. DPFX(DPFPREP, DVF_INFOLEVEL, "looking for main window for pid: %i", param->lppi->dwProcessId);
  269. DWORD dwProcessId;
  270. GetWindowThreadProcessId(hwnd, &dwProcessId);
  271. DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId);
  272. if (dwProcessId == param->lppi->dwProcessId)
  273. {
  274. TCHAR rgtchClassName[64];
  275. GetClassName(hwnd, rgtchClassName, 64);
  276. if (_tcsnicmp(rgtchClassName, _T("Volume Control"), 64) == 0)
  277. {
  278. if (!SetWindowPos(hwnd, HWND_TOP, param->x, param->y, 0, 0, SWP_NOSIZE))
  279. {
  280. Diagnostics_Write(DVF_ERRORLEVEL, "SetWindowPos failed, code: 0x%x", GetLastError());
  281. }
  282. else
  283. {
  284. param->fMoved = TRUE;
  285. }
  286. }
  287. return FALSE;
  288. }
  289. return TRUE;
  290. }
  291. #undef DPF_MODNAME
  292. #define DPF_MODNAME "CSupervisorInfo::SetDeviceFlags"
  293. void CSupervisorInfo::SetDeviceFlags( DWORD dwFlags )
  294. {
  295. m_dwDeviceFlags = dwFlags;
  296. }
  297. #undef DPF_MODNAME
  298. #define DPF_MODNAME "CSupervisorInfo::GetDeviceFlags"
  299. void CSupervisorInfo::GetDeviceFlags( DWORD *pdwFlags ) const
  300. {
  301. *pdwFlags = m_dwDeviceFlags;
  302. }
  303. #undef DPF_MODNAME
  304. #define DPF_MODNAME "CSupervisorInfo::LaunchWindowsVolumeControl"
  305. HRESULT CSupervisorInfo::LaunchWindowsVolumeControl(HWND hwndWizard, BOOL fRecord)
  306. {
  307. DPF_ENTER();
  308. STARTUPINFO si;
  309. ZeroMemory(&si, sizeof(STARTUPINFO));
  310. si.cb = sizeof(STARTUPINFO);
  311. TCHAR ptcharCommand[64];
  312. TCHAR ptcharAppName[MAX_PATH+1];
  313. PROCESS_INFORMATION* lppi;
  314. UINT uiPlayMixerID = 0;
  315. UINT uiCaptureMixerID = 0;
  316. MMRESULT mmr = MMSYSERR_NOERROR;
  317. mmr = mixerGetID( (HMIXEROBJ) (UINT_PTR) m_uiWaveInDeviceId, &uiCaptureMixerID, MIXER_OBJECTF_WAVEIN );
  318. if( mmr != MMSYSERR_NOERROR )
  319. {
  320. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to get capture mixerline mmr=0x%x", mmr );
  321. return DV_OK;
  322. }
  323. mmr = mixerGetID( (HMIXEROBJ) (UINT_PTR) m_uiWaveOutDeviceId, &uiPlayMixerID, MIXER_OBJECTF_WAVEOUT );
  324. if( mmr != MMSYSERR_NOERROR )
  325. {
  326. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to get playback mixerline mmr=0x%x", mmr );
  327. return DV_OK;
  328. }
  329. #ifdef WINNT
  330. GetSystemDirectory(ptcharAppName, MAX_PATH);
  331. #else
  332. GetWindowsDirectory(ptcharAppName, MAX_PATH);
  333. #endif
  334. DWORD dwAppNameFullPathLen=_tcslen(ptcharAppName);
  335. if (ptcharAppName[dwAppNameFullPathLen-1]!='\\')
  336. ptcharAppName[dwAppNameFullPathLen++]='\\';
  337. ptcharAppName[dwAppNameFullPathLen++]=0;
  338. _tcsncat(ptcharAppName, _T("sndvol32.exe"), MAX_PATH-dwAppNameFullPathLen);
  339. if (fRecord)
  340. {
  341. _stprintf(ptcharCommand, _T("sndvol32.exe /R /D %i"), uiCaptureMixerID);
  342. lppi = &m_piSndVol32Record;
  343. }
  344. else
  345. {
  346. _stprintf(ptcharCommand, _T("sndvol32.exe /D %i"), uiPlayMixerID);
  347. lppi = &m_piSndVol32Playback;
  348. }
  349. //if sndvol process has previously been launched
  350. if (lppi->hProcess != NULL)
  351. {
  352. DWORD dwExitCode;
  353. if (GetExitCodeProcess(lppi->hProcess, &dwExitCode) != 0)
  354. {
  355. if (dwExitCode == STILL_ACTIVE)
  356. {
  357. // not dead yet! Don't start another copy,
  358. // but do bring it to the foreground.
  359. SMoveWindowEnumProcParam param;
  360. param.lppi = lppi;
  361. param.fMoved = FALSE;
  362. param.x = 0;
  363. param.y = 0;
  364. EnumWindows(BringToForegroundWindowEnumProc, (LPARAM)&param);
  365. DPF_EXIT();
  366. return DV_OK;
  367. }
  368. // The user terminated the process. Close our handles,
  369. // and zero the process information structure
  370. CloseHandle(lppi->hProcess);
  371. CloseHandle(lppi->hThread);
  372. ZeroMemory(lppi, sizeof(PROCESS_INFORMATION));
  373. }
  374. else
  375. {
  376. // If GetExitCodeProcess fails, assume the handle
  377. // is bad for some reason. Log it, then behave as
  378. // if the process was shut down. At worst, we'll
  379. // have multiple copies of SndVol32 running around.
  380. Diagnostics_Write(DVF_ERRORLEVEL, "GetExitCodeProcess failed, code:0x%x", GetLastError());
  381. // Don't close the handles, they may be bad. If they're
  382. // not, the OS will clean 'em up when the wizard exits.
  383. ZeroMemory(lppi, sizeof(PROCESS_INFORMATION));
  384. }
  385. }
  386. //no current sndvol process, so try and create one
  387. if (lppi->hProcess == NULL)
  388. {
  389. if (!CreateProcess(ptcharAppName, ptcharCommand, NULL, NULL, FALSE, 0, NULL, NULL, &si, lppi))
  390. {
  391. //failed to create the volume control process.
  392. //if it looks like it hasn't been installed pop up a suitable message
  393. if (GetLastError()==ERROR_FILE_NOT_FOUND)
  394. DV_DisplayErrorBox(ERROR_FILE_NOT_FOUND, m_hwndWizard, IDS_ERROR_NOSNDVOL32);
  395. //otherwise we'll generate some debug error but otherwise fail silently
  396. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed tp launched volume control GetLastError %u", GetLastError());
  397. }
  398. else
  399. {
  400. DPFX(DPFPREP, DVF_INFOLEVEL, "Launched volume control, pid:%i", lppi->dwProcessId);
  401. // Find main window for the process we just created and
  402. // move it manually.
  403. //
  404. // Note the race condition - I have no reliable way to wait until
  405. // the main window has been displayed. So, the work around
  406. // (a.k.a. HACK) is to keep looking for it for a while.
  407. // If it hasn't been found by then, we just give up. It's not
  408. // tragic if we don't find it, it just won't be as neat and
  409. // tidy, since the window will come up wherever it was last time.
  410. //
  411. // Note that sndvol32.exe does not accept the STARTF_USEPOSITION
  412. // flag on the PROCESS_INFORMATION structure, so I have to do
  413. // this hack.
  414. //
  415. // In an attempt to let the sndvol32.exe get up and running,
  416. // I call Sleep to relinquish my timeslice.
  417. Sleep(0);
  418. RECT rect;
  419. if (GetWindowRect(hwndWizard, &rect))
  420. {
  421. SMoveWindowEnumProcParam param;
  422. param.lppi = lppi;
  423. param.fMoved = FALSE;
  424. param.x = rect.left;
  425. param.y = rect.top;
  426. int iOffset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYBORDER);
  427. if (m_piSndVol32Record.hProcess == lppi->hProcess)
  428. {
  429. // This is the recording control. Cascade it
  430. // one level down from the wizard main window.
  431. param.x += iOffset;
  432. param.y += iOffset;
  433. }
  434. else
  435. {
  436. // This is the playback control. Cascade it
  437. // two levels down from the wizard main window.
  438. param.x += iOffset*2;
  439. param.y += iOffset*2;
  440. }
  441. // Make twenty attempts to move the window.
  442. // Combined with Sleep(25), this will not
  443. // wait for more than 1/2 second before giving up.
  444. for (int i = 0; i < 20; ++i)
  445. {
  446. EnumWindows(MoveWindowEnumProc, (LPARAM)&param);
  447. if (param.fMoved)
  448. {
  449. // window was moved, break out.
  450. break;
  451. }
  452. // Window was not moved. Wait 25 milliseconds (plus change)
  453. // and try again.
  454. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Attempt to move sndvol32 window failed");
  455. Sleep(25);
  456. }
  457. }
  458. else
  459. {
  460. Diagnostics_Write(DVF_ERRORLEVEL, "GetWindowRect failed");
  461. }
  462. }
  463. }
  464. DPF_EXIT();
  465. return DV_OK;
  466. }
  467. #undef DPF_MODNAME
  468. #define DPF_MODNAME "CloseWindowEnumProc"
  469. BOOL CALLBACK CloseWindowEnumProc(HWND hwnd, LPARAM lParam)
  470. {
  471. DWORD dwProcessId;
  472. DPFX(DPFPREP, DVF_INFOLEVEL, "looking for pid: 0x%p to shutdown", lParam);
  473. GetWindowThreadProcessId(hwnd, &dwProcessId);
  474. DPFX(DPFPREP, DVF_INFOLEVEL, "window: 0x%p has pid: 0x%08x", hwnd, dwProcessId);
  475. if (dwProcessId == (DWORD)lParam)
  476. {
  477. // found it, ask it to close.
  478. DPFX(DPFPREP, DVF_INFOLEVEL, "Sending WM_CLOSE to 0x%p", hwnd);
  479. SendMessage(hwnd, WM_CLOSE, 0, 0);
  480. return FALSE;
  481. }
  482. return TRUE;
  483. }
  484. #undef DPF_MODNAME
  485. #define DPF_MODNAME "CSupervisorInfo::CloseWindowsVolumeControl"
  486. HRESULT CSupervisorInfo::CloseWindowsVolumeControl(BOOL fRecord)
  487. {
  488. DPF_ENTER();
  489. PROCESS_INFORMATION* lppi;
  490. if (fRecord)
  491. {
  492. lppi = &m_piSndVol32Record;
  493. }
  494. else
  495. {
  496. lppi = &m_piSndVol32Playback;
  497. }
  498. if (lppi->hProcess != NULL)
  499. {
  500. DWORD dwExitCode;
  501. if (GetExitCodeProcess(lppi->hProcess, &dwExitCode) != 0)
  502. {
  503. if (dwExitCode == STILL_ACTIVE)
  504. {
  505. DPFX(DPFPREP, DVF_INFOLEVEL, "Attempting to close volume control with pid: %i", lppi->dwProcessId);
  506. // there is currently a volume control showing, find it and
  507. // ask it to close
  508. EnumWindows(CloseWindowEnumProc, lppi->dwProcessId);
  509. // Zero out the process information struct
  510. ZeroMemory(lppi, sizeof(PROCESS_INFORMATION));
  511. }
  512. }
  513. }
  514. DPF_EXIT();
  515. return DV_OK;
  516. }
  517. #undef DPF_MODNAME
  518. #define DPF_MODNAME "CSupervisorInfo::GetWaveOutVolume"
  519. HRESULT CSupervisorInfo::GetWaveOutVolume(DWORD* lpdwVolume)
  520. {
  521. DPF_ENTER();
  522. if (!(m_woCaps.dwSupport & WAVECAPS_VOLUME|WAVECAPS_LRVOLUME))
  523. {
  524. // doesn't support wave out
  525. Diagnostics_Write(DVF_ERRORLEVEL, "Wave device %i does not support volume control", m_uiWaveOutDeviceId);
  526. DPF_EXIT();
  527. return E_FAIL;
  528. }
  529. MMRESULT mmr = waveOutGetVolume((HWAVEOUT) ((UINT_PTR) m_uiWaveOutDeviceId ), lpdwVolume);
  530. if (mmr != MMSYSERR_NOERROR)
  531. {
  532. Diagnostics_Write(DVF_ERRORLEVEL, "waveOutGetVolume failed, code: %i", mmr);
  533. DPF_EXIT();
  534. return E_FAIL;
  535. }
  536. if (m_woCaps.dwSupport & WAVECAPS_LRVOLUME)
  537. {
  538. // has a left and right volume control - average them
  539. *lpdwVolume = (HIWORD(*lpdwVolume) + LOWORD(*lpdwVolume))/2;
  540. }
  541. else
  542. {
  543. // just a mono control - only the low word is significant
  544. *lpdwVolume = LOWORD(*lpdwVolume);
  545. }
  546. DPF_EXIT();
  547. return DV_OK;
  548. }
  549. #undef DPF_MODNAME
  550. #define DPF_MODNAME "CSupervisorInfo::SetWaveOutVolume"
  551. HRESULT CSupervisorInfo::SetWaveOutVolume(DWORD dwVolume)
  552. {
  553. DPF_ENTER();
  554. MMRESULT mmr = waveOutSetVolume((HWAVEOUT) ((UINT_PTR) m_uiWaveOutDeviceId), LOWORD(dwVolume)<<16|LOWORD(dwVolume));
  555. if (mmr != MMSYSERR_NOERROR)
  556. {
  557. DPF_EXIT();
  558. return E_FAIL;
  559. }
  560. DPF_EXIT();
  561. return DV_OK;
  562. }
  563. #undef DPF_MODNAME
  564. #define DPF_MODNAME "CSupervisorInfo::SetRecordVolume"
  565. HRESULT CSupervisorInfo::SetRecordVolume(LONG lVolume)
  566. {
  567. HRESULT hr;
  568. DVCLIENTCONFIG dvcc;
  569. dvcc.dwSize = sizeof(dvcc);
  570. if (m_lpdpvc != NULL)
  571. {
  572. hr = m_lpdpvc->GetClientConfig(&dvcc);
  573. if (FAILED(hr))
  574. {
  575. Diagnostics_Write(DVF_ERRORLEVEL, "GetClientConfig failed, hr:%i", hr);
  576. return hr;
  577. }
  578. dvcc.lRecordVolume = lVolume;
  579. hr = m_lpdpvc->SetClientConfig(&dvcc);
  580. if (FAILED(hr))
  581. {
  582. Diagnostics_Write(DVF_ERRORLEVEL, "SetClientConfig failed, hr:%i", hr);
  583. return hr;
  584. }
  585. }
  586. else
  587. {
  588. return DVERR_INVALIDPOINTER;
  589. }
  590. return DV_OK;
  591. }
  592. #undef DPF_MODNAME
  593. #define DPF_MODNAME "CSupervisorInfo::CancelFullDuplexTest"
  594. HRESULT CSupervisorInfo::CancelFullDuplexTest()
  595. {
  596. HRESULT hrFnc;
  597. HRESULT hr;
  598. DWORD dwRet;
  599. LONG lRet;
  600. hrFnc = DV_OK;
  601. Diagnostics_Write(DVF_ERRORLEVEL,"User cancelled wizard during full duplex test." );
  602. DNEnterCriticalSection(&m_csLock);
  603. // Are we currently in the middle of a full duplex test?
  604. if (m_hFullDuplexThread != NULL)
  605. {
  606. // This flag is periodically checked by the full duplex test
  607. // while it works.
  608. m_fAbortFullDuplex = TRUE;
  609. // wait for the full duplex thread to exit gracefully
  610. DNLeaveCriticalSection(&m_csLock);
  611. dwRet = WaitForMultipleObjects( 1, &m_hFullDuplexThread, FALSE, gc_dwLoopbackTestThreadTimeout);
  612. switch (dwRet)
  613. {
  614. case WAIT_OBJECT_0:
  615. // the full duplex thread is now done, so continue...
  616. DNEnterCriticalSection(&m_csLock);
  617. break;
  618. case WAIT_TIMEOUT:
  619. // The full duplex thread is not cooperating - get tough with it.
  620. DNEnterCriticalSection(&m_csLock);
  621. hr = m_sipc.TerminateChildProcesses();
  622. if (FAILED(hr))
  623. {
  624. Diagnostics_Write(DVF_ERRORLEVEL, "TerminateChildProcesses failed, code: 0x%x", hr);
  625. hrFnc = hr;
  626. }
  627. if (!TerminateThread(m_hFullDuplexThread, hr))
  628. {
  629. lRet = GetLastError();
  630. Diagnostics_Write(DVF_ERRORLEVEL, "TerminateThread failed, code: 0x%x", lRet);
  631. hrFnc = DVERR_GENERIC;
  632. }
  633. break;
  634. default:
  635. // this is not supposed to happen. Note it, terminate everything,
  636. // and continue.
  637. DNEnterCriticalSection(&m_csLock);
  638. if (dwRet == WAIT_ABANDONED)
  639. {
  640. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject abandoned unexpectedly");
  641. hrFnc = DVERR_GENERIC;
  642. }
  643. else
  644. {
  645. lRet = GetLastError();
  646. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject failed, code: 0x%x", lRet);
  647. hrFnc = DVERR_GENERIC;
  648. }
  649. hr = m_sipc.TerminateChildProcesses();
  650. if (FAILED(hr))
  651. {
  652. Diagnostics_Write(DVF_ERRORLEVEL, "TerminateChildProcesses failed, code: 0x%x", hr);
  653. hrFnc = hr;
  654. }
  655. if (!TerminateThread(m_hFullDuplexThread, hr))
  656. {
  657. lRet = GetLastError();
  658. Diagnostics_Write(DVF_ERRORLEVEL, "TerminateThread failed, code: 0x%x", lRet);
  659. hrFnc = DVERR_GENERIC;
  660. }
  661. break;
  662. }
  663. // Close the full duplex thread handle
  664. hr = WaitForFullDuplexThreadExitCode();
  665. if (FAILED(hr))
  666. {
  667. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForFullDuplexThreadExitCode failed, code: 0x%x", hr);
  668. hrFnc = hr;
  669. }
  670. // cleanup the IPC objects
  671. hr = DeinitIPC();
  672. if (FAILED(hr))
  673. {
  674. Diagnostics_Write(DVF_ERRORLEVEL, "DeinitIPC failed, code: 0x%x", hr);
  675. hrFnc = hr;
  676. }
  677. }
  678. DNLeaveCriticalSection(&m_csLock);
  679. return hrFnc;
  680. }
  681. #undef DPF_MODNAME
  682. #define DPF_MODNAME "CSupervisorInfo::CancelLoopbackTest"
  683. HRESULT CSupervisorInfo::CancelLoopbackTest()
  684. {
  685. HRESULT hr = DV_OK;
  686. Diagnostics_Write(DVF_ERRORLEVEL,"User cancelled wizard during loopback test" );
  687. DNEnterCriticalSection(&m_csLock);
  688. // Are we currently in the middle of a loopback test?
  689. if (m_hLoopbackThread != NULL)
  690. {
  691. // If the loopback thread handle is not null, the mic test may still
  692. // be going on, in which case we want to set that flag to
  693. // REGVAL_NOTRUN, since the test was not completed.
  694. DWORD dwRegVal;
  695. GetMicDetected(&dwRegVal);
  696. if (dwRegVal == REGVAL_CRASHED)
  697. {
  698. SetMicDetected(REGVAL_NOTRUN);
  699. }
  700. DNLeaveCriticalSection(&m_csLock); // ShutdownLoopbackThread has its own guard
  701. hr = ShutdownLoopbackThread();
  702. DNEnterCriticalSection(&m_csLock);
  703. if (FAILED(hr))
  704. {
  705. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr);
  706. }
  707. }
  708. DNLeaveCriticalSection(&m_csLock);
  709. return hr;
  710. }
  711. #undef DPF_MODNAME
  712. #define DPF_MODNAME "CSupervisorInfo::Cancel"
  713. HRESULT CSupervisorInfo::Cancel()
  714. {
  715. DPF_ENTER();
  716. DWORD dwRet;
  717. HRESULT hr;
  718. LONG lRet;
  719. HRESULT hrFnc;
  720. BOOL fDone;
  721. BOOL fGotMsg;
  722. BOOL fWelcomeNext;
  723. MSG msg;
  724. DNEnterCriticalSection(&m_csLock);
  725. hrFnc = DV_OK;
  726. // close any open volume controls
  727. CloseWindowsVolumeControl(TRUE);
  728. CloseWindowsVolumeControl(FALSE);
  729. // The cancel button can be hit at any time.
  730. // We are not in a known state. This function
  731. // has to figure it out from the member variables.
  732. // How fun.
  733. DNLeaveCriticalSection(&m_csLock); // CancelFullDuplexTest has it's own guard
  734. hrFnc = CancelFullDuplexTest();
  735. DNEnterCriticalSection(&m_csLock);
  736. // Are we currently in the middle of a loopback test?
  737. if (m_hLoopbackThread != NULL)
  738. {
  739. DNLeaveCriticalSection(&m_csLock); // ShutdownLoopbackThread has its own guard
  740. hr = ShutdownLoopbackThread();
  741. DNEnterCriticalSection(&m_csLock);
  742. if (FAILED(hr))
  743. {
  744. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr);
  745. hrFnc = hr;
  746. }
  747. }
  748. // Reset the registry to the "test not yet run" state
  749. // but only if the user moved past the welcome page
  750. GetWelcomeNext(&fWelcomeNext);
  751. if (fWelcomeNext)
  752. {
  753. hr = SetHalfDuplex(REGVAL_NOTRUN);
  754. if (FAILED(hr))
  755. {
  756. Diagnostics_Write(DVF_ERRORLEVEL, "SetHalfDuplex failed, code: %i", hr);
  757. hrFnc = hr;
  758. }
  759. hr = SetFullDuplex(REGVAL_NOTRUN);
  760. if (FAILED(hr))
  761. {
  762. Diagnostics_Write(DVF_ERRORLEVEL, "SetFullDuplex failed, code: %i", hr);
  763. hrFnc = hr;
  764. }
  765. hr = SetMicDetected(REGVAL_NOTRUN);
  766. if (FAILED(hr))
  767. {
  768. Diagnostics_Write(DVF_ERRORLEVEL, "SetMicDetected failed, code: %i", hr);
  769. hrFnc = hr;
  770. }
  771. }
  772. // record the fact that the wizard was bailed out of
  773. SetUserCancel();
  774. DNLeaveCriticalSection(&m_csLock);
  775. DPF_EXIT();
  776. return hrFnc;
  777. }
  778. #undef DPF_MODNAME
  779. #define DPF_MODNAME "CSupervisorInfo::Abort"
  780. HRESULT CSupervisorInfo::Abort(HWND hDlg, HRESULT hrDlg)
  781. {
  782. // This is the function called whenever a fatal error is hit while in the wizard
  783. DPF_ENTER();
  784. DWORD dwRet;
  785. HRESULT hr;
  786. LONG lRet;
  787. HRESULT hrFnc;
  788. BOOL fDone;
  789. BOOL fGotMsg;
  790. BOOL fWelcomeNext;
  791. MSG msg;
  792. HWND hwndParent = NULL;
  793. hrFnc = DV_OK;
  794. // close any open volume controls
  795. DNEnterCriticalSection(&m_csLock);
  796. CloseWindowsVolumeControl(TRUE);
  797. CloseWindowsVolumeControl(FALSE);
  798. DNLeaveCriticalSection(&m_csLock);
  799. // The cancel button can be hit at any time.
  800. // We are not in a known state. This function
  801. // has to figure it out from the member variables.
  802. // How fun.
  803. // CancelFullDuplexTest has it's own guard
  804. hrFnc = CancelFullDuplexTest();
  805. // Are we currently in the middle of a loopback test?
  806. DNEnterCriticalSection(&m_csLock);
  807. if (m_hLoopbackThread != NULL)
  808. {
  809. DNLeaveCriticalSection(&m_csLock); // ShutdownLoopbackThread has its own guard
  810. hr = ShutdownLoopbackThread();
  811. if (FAILED(hr))
  812. {
  813. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr);
  814. hrFnc = hr;
  815. }
  816. }
  817. else
  818. DNLeaveCriticalSection(&m_csLock);
  819. // Leave the registry alone - this will signal that there was
  820. // an error to the next wizard run, assuming we're still in
  821. // the middle of a test. If we've actually gotten far enough
  822. // along to record a pass in the registry, so be it.
  823. // Call EndDialog to forcibly bail out of the wizard.
  824. Diagnostics_Write(DVF_ERRORLEVEL, "Attempting to abort wizard, hr: %i", hrDlg);
  825. hwndParent = GetParent(hDlg);
  826. if (IsWindow(hwndParent))
  827. {
  828. PostMessage(hwndParent, WM_CLOSE, (WPARAM)NULL, (LPARAM)NULL);
  829. /*
  830. // EndDialog does not work because we are in a property sheet
  831. if (!EndDialog(hwndParent, hrDlg))
  832. {
  833. Diagnostics_Write(DVF_ERRORLEVEL, "EndDialog failed, code: %i:", GetLastError());
  834. }
  835. */
  836. }
  837. else
  838. {
  839. Diagnostics_Write(DVF_ERRORLEVEL, "Unable to get a handle to the wizard!");
  840. }
  841. DPF_EXIT();
  842. return hrFnc;
  843. }
  844. #undef DPF_MODNAME
  845. #define DPF_MODNAME "CSupervisorInfo::Finish"
  846. HRESULT CSupervisorInfo::Finish()
  847. {
  848. DPF_ENTER();
  849. DWORD dwRet;
  850. HRESULT hr;
  851. LONG lRet;
  852. HRESULT hrFnc;
  853. DWORD dwValue;
  854. DNEnterCriticalSection(&m_csLock);
  855. hrFnc = DV_OK;
  856. // close any open volume controls
  857. CloseWindowsVolumeControl(TRUE);
  858. CloseWindowsVolumeControl(FALSE);
  859. DNLeaveCriticalSection(&m_csLock);
  860. DPF_EXIT();
  861. return hrFnc;
  862. }
  863. #undef DPF_MODNAME
  864. #define DPF_MODNAME "CSupervisorInfo::CreateFullDuplexThread"
  865. HRESULT CSupervisorInfo::CreateFullDuplexThread()
  866. {
  867. DPF_ENTER();
  868. HRESULT hr;
  869. LONG lRet;
  870. DWORD dwThreadId;
  871. DNEnterCriticalSection(&m_csLock);
  872. // Null out the interface pointer
  873. m_lpdpvc = NULL;
  874. if (m_hFullDuplexThread != NULL)
  875. {
  876. Diagnostics_Write(DVF_ERRORLEVEL, "m_hFullDuplexThread not NULL");
  877. hr = DVERR_GENERIC;
  878. goto error_cleanup;
  879. }
  880. m_hFullDuplexThread = CreateThread(NULL, 0, FullDuplexTestThreadProc, (LPVOID)this, NULL, &dwThreadId);
  881. if (m_hFullDuplexThread == NULL)
  882. {
  883. // error, log it and bail
  884. lRet = GetLastError();
  885. Diagnostics_Write(DVF_ERRORLEVEL, "CreateThread failed, code: %i", lRet);
  886. hr = DVERR_GENERIC;
  887. goto error_cleanup;
  888. }
  889. DNLeaveCriticalSection(&m_csLock);
  890. DPF_EXIT();
  891. return DV_OK;
  892. error_cleanup:
  893. DNLeaveCriticalSection(&m_csLock);
  894. DPF_EXIT();
  895. return hr;
  896. }
  897. #undef DPF_MODNAME
  898. #define DPF_MODNAME "CSupervisorInfo::WaitForFullDuplexThreadExitCode"
  899. HRESULT CSupervisorInfo::WaitForFullDuplexThreadExitCode()
  900. {
  901. DPF_ENTER();
  902. HRESULT hr;
  903. HRESULT hrFnc;
  904. LONG lRet;
  905. DWORD dwThreadId;
  906. DWORD dwRet;
  907. DNEnterCriticalSection(&m_csLock);
  908. if (m_hFullDuplexThread == NULL)
  909. {
  910. Diagnostics_Write(DVF_ERRORLEVEL, "m_hFullDuplexThread is NULL");
  911. hr = DVERR_GENERIC;
  912. goto error_cleanup;
  913. }
  914. dwRet = WaitForSingleObject(m_hFullDuplexThread, gc_dwChildWaitTimeout);
  915. switch(dwRet)
  916. {
  917. case WAIT_OBJECT_0:
  918. break;
  919. case WAIT_TIMEOUT:
  920. Diagnostics_Write(DVF_ERRORLEVEL, "Timed out waiting for full duplex test thread to exit - terminating forcibly");
  921. TerminateThread(m_hFullDuplexThread, DVERR_GENERIC);
  922. hr = DVERR_GENERIC;
  923. goto error_cleanup;
  924. default:
  925. Diagnostics_Write(DVF_ERRORLEVEL, "Unknown error waiting for full duplex test thread to exit - terminating forcibly");
  926. TerminateThread(m_hFullDuplexThread, DVERR_GENERIC);
  927. hr = DVERR_GENERIC;
  928. goto error_cleanup;
  929. }
  930. if (!GetExitCodeThread(m_hFullDuplexThread, (DWORD*)&hrFnc))
  931. {
  932. Diagnostics_Write(DVF_ERRORLEVEL, "Error retrieving full duplex test thread's exit code");
  933. hr = DVERR_GENERIC;
  934. goto error_cleanup;
  935. }
  936. if (!CloseHandle(m_hFullDuplexThread))
  937. {
  938. // error, log it and bail
  939. lRet = GetLastError();
  940. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  941. hr = DVERR_GENERIC;
  942. goto error_cleanup;
  943. }
  944. m_hFullDuplexThread = NULL;
  945. DNLeaveCriticalSection(&m_csLock);
  946. DPF_EXIT();
  947. return hrFnc;
  948. error_cleanup:
  949. DNLeaveCriticalSection(&m_csLock);
  950. DPF_EXIT();
  951. return hr;
  952. }
  953. #undef DPF_MODNAME
  954. #define DPF_MODNAME "CSupervisorInfo::CreateLoopbackThread"
  955. HRESULT CSupervisorInfo::CreateLoopbackThread()
  956. {
  957. DPF_ENTER();
  958. HRESULT hr;
  959. LONG lRet;
  960. DWORD dwThreadId;
  961. DNEnterCriticalSection(&m_csLock);
  962. m_hLoopbackShutdownEvent = NULL;
  963. if (m_hLoopbackThread != NULL)
  964. {
  965. // The loopback test is already running.
  966. // Just dump a warning and return pending.
  967. DPFX(DPFPREP, DVF_WARNINGLEVEL, "m_hLoopbackThread not NULL");
  968. hr = DVERR_PENDING;
  969. goto error_cleanup;
  970. }
  971. // create an event the loopback thread signals just before it exits
  972. m_hLoopbackThreadExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  973. if (m_hLoopbackThreadExitEvent == NULL)
  974. {
  975. // error, log it and bail
  976. lRet = GetLastError();
  977. Diagnostics_Write(DVF_ERRORLEVEL, "CreateEvent failed, code: %i", lRet);
  978. hr = DVERR_GENERIC;
  979. goto error_cleanup;
  980. }
  981. // create an event the loopback thread listens for to shutdown
  982. m_hLoopbackShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  983. if (m_hLoopbackShutdownEvent == NULL)
  984. {
  985. // error, log it and bail
  986. lRet = GetLastError();
  987. Diagnostics_Write(DVF_ERRORLEVEL, "CreateEvent failed, code: %i", lRet);
  988. hr = DVERR_GENERIC;
  989. goto error_cleanup;
  990. }
  991. m_hLoopbackThread = CreateThread(NULL, 0, LoopbackTestThreadProc, (LPVOID)this, NULL, &dwThreadId);
  992. if (m_hLoopbackThread == NULL)
  993. {
  994. // error, log it and bail
  995. lRet = GetLastError();
  996. Diagnostics_Write(DVF_ERRORLEVEL, "CreateThread failed, code: %i", lRet);
  997. hr = DVERR_GENERIC;
  998. goto error_cleanup;
  999. }
  1000. DNLeaveCriticalSection(&m_csLock);
  1001. DPF_EXIT();
  1002. return DV_OK;
  1003. error_cleanup:
  1004. if (m_hLoopbackThreadExitEvent != NULL)
  1005. {
  1006. CloseHandle(m_hLoopbackThreadExitEvent);
  1007. m_hLoopbackThreadExitEvent = NULL;
  1008. }
  1009. if (m_hLoopbackShutdownEvent != NULL)
  1010. {
  1011. CloseHandle(m_hLoopbackShutdownEvent);
  1012. m_hLoopbackShutdownEvent = NULL;
  1013. }
  1014. DNLeaveCriticalSection(&m_csLock);
  1015. DPF_EXIT();
  1016. return hr;
  1017. }
  1018. #undef DPF_MODNAME
  1019. #define DPF_MODNAME "CSupervisorInfo::WaitForLoopbackShutdownEvent"
  1020. HRESULT CSupervisorInfo::WaitForLoopbackShutdownEvent()
  1021. {
  1022. DPF_ENTER();
  1023. HRESULT hr;
  1024. LONG lRet;
  1025. DWORD dwThreadId;
  1026. DWORD dwRet;
  1027. HANDLE hEvent;
  1028. DNEnterCriticalSection(&m_csLock);
  1029. hEvent = m_hLoopbackShutdownEvent;
  1030. DNLeaveCriticalSection(&m_csLock);
  1031. dwRet = WaitForSingleObject(hEvent, INFINITE);
  1032. DNEnterCriticalSection(&m_csLock);
  1033. switch (dwRet)
  1034. {
  1035. case WAIT_OBJECT_0:
  1036. // expected behavior, continue
  1037. break;
  1038. case WAIT_TIMEOUT:
  1039. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject timed out unexpectedly");
  1040. hr = DVERR_GENERIC;
  1041. goto error_cleanup;
  1042. case WAIT_ABANDONED:
  1043. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject abandoned unexpectedly");
  1044. hr = DVERR_GENERIC;
  1045. goto error_cleanup;
  1046. default:
  1047. lRet = GetLastError();
  1048. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForSingleObject returned unknown code, GetLastError(): %i", lRet);
  1049. hr = DVERR_GENERIC;
  1050. goto error_cleanup;
  1051. }
  1052. DNLeaveCriticalSection(&m_csLock);
  1053. DPF_EXIT();
  1054. return DV_OK;
  1055. error_cleanup:
  1056. DNLeaveCriticalSection(&m_csLock);
  1057. DPF_EXIT();
  1058. return hr;
  1059. }
  1060. #undef DPF_MODNAME
  1061. #define DPF_MODNAME "CSupervisorInfo::SignalLoopbackThreadDone"
  1062. HRESULT CSupervisorInfo::SignalLoopbackThreadDone()
  1063. {
  1064. DPF_ENTER();
  1065. HRESULT hr;
  1066. LONG lRet;
  1067. HANDLE hEvent;
  1068. DNEnterCriticalSection(&m_csLock);
  1069. hEvent = m_hLoopbackThreadExitEvent;
  1070. DNLeaveCriticalSection(&m_csLock);
  1071. if (!SetEvent(hEvent))
  1072. {
  1073. lRet = GetLastError();
  1074. Diagnostics_Write(DVF_ERRORLEVEL, "SetEvent failed, code: %i", lRet);
  1075. hr = DVERR_GENERIC;
  1076. goto error_cleanup;
  1077. }
  1078. DPF_EXIT();
  1079. return DV_OK;
  1080. error_cleanup:
  1081. DPF_EXIT();
  1082. return hr;
  1083. }
  1084. #undef DPF_MODNAME
  1085. #define DPF_MODNAME "CSupervisorInfo::ShutdownLoopbackThread"
  1086. HRESULT CSupervisorInfo::ShutdownLoopbackThread()
  1087. {
  1088. DPF_ENTER();
  1089. HRESULT hr;
  1090. LONG lRet;
  1091. DWORD dwThreadId;
  1092. DWORD dwRet;
  1093. BOOL fDone;
  1094. BOOL fGotMsg;
  1095. MSG msg;
  1096. HANDLE rghHandle[2];
  1097. HANDLE hEvent;
  1098. DNEnterCriticalSection(&m_csLock);
  1099. if (m_hLoopbackThread == NULL)
  1100. {
  1101. Diagnostics_Write(DVF_ERRORLEVEL, "m_hLoopbackThread is NULL");
  1102. hr = DVERR_GENERIC;
  1103. goto error_cleanup;
  1104. }
  1105. if (!SetEvent(m_hLoopbackShutdownEvent))
  1106. {
  1107. lRet = GetLastError();
  1108. Diagnostics_Write(DVF_ERRORLEVEL, "SetEvent failed, code: %i", lRet);
  1109. hr = DVERR_GENERIC;
  1110. goto error_cleanup;
  1111. }
  1112. /*
  1113. rghHandle[0] = m_hLoopbackThreadExitEvent;
  1114. rghHandle[1] = m_hLoopbackThread;
  1115. */
  1116. hEvent = m_hLoopbackThreadExitEvent;
  1117. DNLeaveCriticalSection(&m_csLock);
  1118. fDone = FALSE;
  1119. while (!fDone)
  1120. {
  1121. dwRet = WaitForSingleObject(hEvent, gc_dwLoopbackTestThreadTimeout);
  1122. switch(dwRet)
  1123. {
  1124. case WAIT_OBJECT_0:
  1125. DNEnterCriticalSection(&m_csLock);
  1126. fDone = TRUE;
  1127. break;
  1128. case WAIT_ABANDONED:
  1129. default:
  1130. // not supposed to be possible, but treat both like a timeout.
  1131. case WAIT_TIMEOUT:
  1132. DNEnterCriticalSection(&m_csLock);
  1133. hr = DVERR_TIMEOUT;
  1134. goto error_cleanup;
  1135. break;
  1136. }
  1137. /*
  1138. dwRet = MsgWaitForMultipleObjects(2, rghHandle, FALSE, gc_dwLoopbackTestThreadTimeout, QS_ALLINPUT);
  1139. switch (dwRet)
  1140. {
  1141. case WAIT_OBJECT_0:
  1142. case WAIT_OBJECT_0 + 1:
  1143. // expected result, continue...
  1144. DNEnterCriticalSection(&m_csLock);
  1145. fDone = TRUE;
  1146. break;
  1147. case WAIT_TIMEOUT:
  1148. // loopback thread is not behaving, jump to
  1149. // the error block where it will be terminated forcibly
  1150. DNEnterCriticalSection(&m_csLock);
  1151. hr = DVERR_TIMEOUT;
  1152. goto error_cleanup;
  1153. break;
  1154. case WAIT_OBJECT_0 + 2:
  1155. // One or more windows messages have been posted to this thread's
  1156. // message queue. Deal with 'em.
  1157. fGotMsg = TRUE;
  1158. while( fGotMsg )
  1159. {
  1160. fGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
  1161. if( fGotMsg )
  1162. {
  1163. TranslateMessage( &msg );
  1164. DispatchMessage( &msg );
  1165. }
  1166. }
  1167. break;
  1168. default:
  1169. if (dwRet == WAIT_ABANDONED)
  1170. {
  1171. Diagnostics_Write(DVF_ERRORLEVEL, "MsgWaitForMultipleObjects abandoned unexpectedly");
  1172. }
  1173. else
  1174. {
  1175. lRet = GetLastError();
  1176. Diagnostics_Write(DVF_ERRORLEVEL, "MsgWaitForMultipleObjects failed, code: %i");
  1177. }
  1178. DNEnterCriticalSection(&m_csLock);
  1179. hr = DVERR_TIMEOUT;
  1180. goto error_cleanup;
  1181. break;
  1182. }
  1183. */
  1184. }
  1185. if (!CloseHandle(m_hLoopbackThread))
  1186. {
  1187. // error, log it and bail
  1188. lRet = GetLastError();
  1189. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  1190. m_hLoopbackThread = NULL;
  1191. hr = DVERR_GENERIC;
  1192. goto error_cleanup;
  1193. }
  1194. m_hLoopbackThread = NULL;
  1195. if (!CloseHandle(m_hLoopbackThreadExitEvent))
  1196. {
  1197. // error, log it and bail
  1198. lRet = GetLastError();
  1199. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  1200. m_hLoopbackThreadExitEvent = NULL;
  1201. hr = DVERR_GENERIC;
  1202. goto error_cleanup;
  1203. }
  1204. m_hLoopbackThreadExitEvent = NULL;
  1205. if (!CloseHandle(m_hLoopbackShutdownEvent))
  1206. {
  1207. // error, log it and bail
  1208. lRet = GetLastError();
  1209. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  1210. m_hLoopbackShutdownEvent = NULL;
  1211. hr = DVERR_GENERIC;
  1212. goto error_cleanup;
  1213. }
  1214. m_hLoopbackShutdownEvent = NULL;
  1215. DNLeaveCriticalSection(&m_csLock);
  1216. DPF_EXIT();
  1217. return DV_OK;
  1218. error_cleanup:
  1219. if (m_hLoopbackThread != NULL)
  1220. {
  1221. TerminateThread(m_hLoopbackThread, DVERR_GENERIC);
  1222. CloseHandle(m_hLoopbackThread);
  1223. m_hLoopbackThread = NULL;
  1224. }
  1225. if (m_hLoopbackThreadExitEvent != NULL)
  1226. {
  1227. CloseHandle(m_hLoopbackThreadExitEvent);
  1228. m_hLoopbackThreadExitEvent = NULL;
  1229. }
  1230. if (m_hLoopbackShutdownEvent != NULL)
  1231. {
  1232. CloseHandle(m_hLoopbackShutdownEvent);
  1233. m_hLoopbackShutdownEvent = NULL;
  1234. }
  1235. DNLeaveCriticalSection(&m_csLock);
  1236. DPF_EXIT();
  1237. return hr;
  1238. }
  1239. #undef DPF_MODNAME
  1240. #define DPF_MODNAME "CSupervisorInfo::SetFullDuplex"
  1241. HRESULT CSupervisorInfo::SetFullDuplex(DWORD dwFullDuplex)
  1242. {
  1243. DPF_ENTER();
  1244. HRESULT hr = DV_OK;
  1245. HKEY hk;
  1246. LONG lRet;
  1247. DNEnterCriticalSection(&m_csLock);
  1248. if (!m_creg.WriteDWORD(gc_wszValueName_FullDuplex, dwFullDuplex))
  1249. {
  1250. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::WriteDWORD failed");
  1251. hr = DVERR_GENERIC;
  1252. }
  1253. else
  1254. {
  1255. // Flush the registry operations to ensure they
  1256. // are written. Otherwise we may not detect a crash!
  1257. hk = m_creg.GetHandle();
  1258. lRet = RegFlushKey(hk);
  1259. if (lRet != ERROR_SUCCESS)
  1260. {
  1261. Diagnostics_Write(DVF_ERRORLEVEL, "RegFlushKey failed");
  1262. hr = DVERR_GENERIC;
  1263. }
  1264. }
  1265. DNLeaveCriticalSection(&m_csLock);
  1266. DPF_EXIT();
  1267. return hr;
  1268. }
  1269. #undef DPF_MODNAME
  1270. #define DPF_MODNAME "CSupervisorInfo::GetFullDuplex"
  1271. HRESULT CSupervisorInfo::GetFullDuplex(DWORD* pdwFullDuplex)
  1272. {
  1273. DPF_ENTER();
  1274. HRESULT hr = DV_OK;
  1275. DNEnterCriticalSection(&m_csLock);
  1276. if (!m_creg.ReadDWORD(gc_wszValueName_FullDuplex, pdwFullDuplex))
  1277. {
  1278. // registry key is not present
  1279. *pdwFullDuplex = 0;
  1280. hr = DVERR_GENERIC;
  1281. }
  1282. if( *pdwFullDuplex > REGVAL_MAXVALID )
  1283. {
  1284. *pdwFullDuplex = 0;
  1285. hr = DVERR_GENERIC;
  1286. }
  1287. DNLeaveCriticalSection(&m_csLock);
  1288. DPF_EXIT();
  1289. return hr;
  1290. }
  1291. #undef DPF_MODNAME
  1292. #define DPF_MODNAME "CSupervisorInfo::SetHalfDuplex"
  1293. HRESULT CSupervisorInfo::SetHalfDuplex(DWORD dwHalfDuplex)
  1294. {
  1295. DPF_ENTER();
  1296. HRESULT hr = DV_OK;
  1297. LONG lRet;
  1298. HKEY hk;
  1299. DNEnterCriticalSection(&m_csLock);
  1300. if (!m_creg.WriteDWORD(gc_wszValueName_HalfDuplex, dwHalfDuplex))
  1301. {
  1302. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::WriteDWORD failed");
  1303. hr = DVERR_GENERIC;
  1304. }
  1305. else
  1306. {
  1307. // Flush the registry operations to ensure they
  1308. // are written. Otherwise we may not detect a crash!
  1309. hk = m_creg.GetHandle();
  1310. lRet = RegFlushKey(hk);
  1311. if (lRet != ERROR_SUCCESS)
  1312. {
  1313. Diagnostics_Write(DVF_ERRORLEVEL, "RegFlushKey failed");
  1314. hr = DVERR_GENERIC;
  1315. }
  1316. }
  1317. DNLeaveCriticalSection(&m_csLock);
  1318. DPF_EXIT();
  1319. return hr;
  1320. }
  1321. #undef DPF_MODNAME
  1322. #define DPF_MODNAME "CSupervisorInfo::GetHalfDuplex"
  1323. HRESULT CSupervisorInfo::GetHalfDuplex(DWORD* pdwHalfDuplex)
  1324. {
  1325. DPF_ENTER();
  1326. HRESULT hr = DV_OK;
  1327. DNEnterCriticalSection(&m_csLock);
  1328. if (!m_creg.ReadDWORD(gc_wszValueName_HalfDuplex, pdwHalfDuplex))
  1329. {
  1330. // registry key is not present
  1331. *pdwHalfDuplex = 0;
  1332. hr = DVERR_GENERIC;
  1333. }
  1334. if( *pdwHalfDuplex > REGVAL_MAXVALID )
  1335. {
  1336. *pdwHalfDuplex = 0;
  1337. hr = DVERR_GENERIC;
  1338. }
  1339. DNLeaveCriticalSection(&m_csLock);
  1340. DPF_EXIT();
  1341. return hr;
  1342. }
  1343. #undef DPF_MODNAME
  1344. #define DPF_MODNAME "CSupervisorInfo::SetMicDetected"
  1345. HRESULT CSupervisorInfo::SetMicDetected(DWORD dwMicDetected)
  1346. {
  1347. DPF_ENTER();
  1348. HRESULT hr = DV_OK;
  1349. LONG lRet;
  1350. HKEY hk;
  1351. DNEnterCriticalSection(&m_csLock);
  1352. if (!m_creg.WriteDWORD(gc_wszValueName_MicDetected, dwMicDetected))
  1353. {
  1354. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::WriteDWORD failed");
  1355. hr = DVERR_GENERIC;
  1356. }
  1357. else
  1358. {
  1359. // Flush the registry operations to ensure they
  1360. // are written. Otherwise we may not detect a crash!
  1361. hk = m_creg.GetHandle();
  1362. lRet = RegFlushKey(hk);
  1363. if (lRet != ERROR_SUCCESS)
  1364. {
  1365. Diagnostics_Write(DVF_ERRORLEVEL, "RegFlushKey failed");
  1366. hr = DVERR_GENERIC;
  1367. }
  1368. }
  1369. DNLeaveCriticalSection(&m_csLock);
  1370. DPF_EXIT();
  1371. return hr;
  1372. }
  1373. #undef DPF_MODNAME
  1374. #define DPF_MODNAME "CSupervisorInfo::GetMicDetected"
  1375. HRESULT CSupervisorInfo::GetMicDetected(DWORD* pdwMicDetected)
  1376. {
  1377. DPF_ENTER();
  1378. HRESULT hr = DV_OK;
  1379. DNEnterCriticalSection(&m_csLock);
  1380. if (!m_creg.ReadDWORD(gc_wszValueName_MicDetected, pdwMicDetected))
  1381. {
  1382. // registry key is not present
  1383. *pdwMicDetected = 0;
  1384. hr = DVERR_GENERIC;
  1385. }
  1386. if( *pdwMicDetected > REGVAL_MAXVALID )
  1387. {
  1388. *pdwMicDetected = 0;
  1389. hr = DVERR_GENERIC;
  1390. }
  1391. DNLeaveCriticalSection(&m_csLock);
  1392. DPF_EXIT();
  1393. return hr;
  1394. }
  1395. #undef DPF_MODNAME
  1396. #define DPF_MODNAME "CSupervisorInfo::QueryFullDuplex"
  1397. HRESULT CSupervisorInfo::QueryFullDuplex()
  1398. {
  1399. DPF_ENTER();
  1400. HRESULT hr;
  1401. DWORD dwFullDuplex;
  1402. DWORD dwHalfDuplex;
  1403. DWORD dwMicDetected;
  1404. DNEnterCriticalSection(&m_csLock);
  1405. if (!m_creg.ReadDWORD(gc_wszValueName_HalfDuplex, &dwHalfDuplex))
  1406. {
  1407. // registry key is not present - setup has not run
  1408. DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex key not found in registry");
  1409. hr = DVERR_RUNSETUP;
  1410. goto error_cleanup;
  1411. }
  1412. // Handle bad values from the registry
  1413. if( dwHalfDuplex > REGVAL_MAXVALID )
  1414. {
  1415. dwHalfDuplex = REGVAL_NOTRUN;
  1416. }
  1417. switch (dwHalfDuplex)
  1418. {
  1419. case REGVAL_NOTRUN:
  1420. // test not run
  1421. DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = 0; test not run");
  1422. hr = DVERR_RUNSETUP;
  1423. goto error_cleanup;
  1424. case REGVAL_CRASHED:
  1425. // test crashed out!
  1426. DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = 1; test crashed");
  1427. hr = DVERR_SOUNDINITFAILURE;
  1428. goto error_cleanup;
  1429. case REGVAL_FAILED:
  1430. // test failed gracefully
  1431. DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = 2; test failed gracefully");
  1432. hr = DVERR_SOUNDINITFAILURE;
  1433. goto error_cleanup;
  1434. case REGVAL_PASSED:
  1435. // test passed
  1436. DPFX(DPFPREP, DVF_INFOLEVEL, "HalfDuplex = 3; test passed");
  1437. break;
  1438. default:
  1439. // bad key value - return run setup
  1440. DPFX(DPFPREP, DVF_WARNINGLEVEL, "HalfDuplex = %i; bad key value!", dwHalfDuplex);
  1441. hr = DVERR_RUNSETUP;
  1442. goto error_cleanup;
  1443. }
  1444. if (!m_creg.ReadDWORD(gc_wszValueName_FullDuplex, &dwFullDuplex))
  1445. {
  1446. // registry key is not present - very odd.
  1447. // however, since we at least passed half duplex to get
  1448. // here, we'll return half duplex
  1449. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex key not found in registry");
  1450. hr = DV_HALFDUPLEX;
  1451. goto error_cleanup;
  1452. }
  1453. // Handle bad values from the registry
  1454. if( dwFullDuplex > REGVAL_MAXVALID )
  1455. {
  1456. dwFullDuplex = REGVAL_NOTRUN;
  1457. }
  1458. switch (dwFullDuplex)
  1459. {
  1460. case REGVAL_NOTRUN:
  1461. // Test not run - this is very odd, considering that
  1462. // in order to get here, the half duplex test must have
  1463. // been run and passed. Return half duplex.
  1464. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = 0; test not run");
  1465. hr = DV_HALFDUPLEX;
  1466. goto error_cleanup;
  1467. case REGVAL_CRASHED:
  1468. // test crashed out! - They tried, and going further
  1469. // wouldn't help, so certify them for half duplex
  1470. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = 1; test crashed");
  1471. hr = DV_HALFDUPLEX;
  1472. goto error_cleanup;
  1473. case REGVAL_FAILED:
  1474. // test failed gracefully - mic test would not have been
  1475. // run, certify them for half duplex.
  1476. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = 2; test failed gracefully");
  1477. hr = DV_HALFDUPLEX;
  1478. goto error_cleanup;
  1479. case REGVAL_PASSED:
  1480. // test passed
  1481. DPFX(DPFPREP, DVF_INFOLEVEL, "FullDuplex = 3; test passed");
  1482. break;
  1483. default:
  1484. // bad key value - but the system can at least do
  1485. // half duplex, so certify them for half duplex
  1486. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex = %i; bad key value!", dwFullDuplex);
  1487. hr = DV_HALFDUPLEX;
  1488. goto error_cleanup;
  1489. }
  1490. // From this point on, we know the full duplex test was ok.
  1491. // However, in order to get a full duplex pass, the mic must
  1492. // also have been detected.
  1493. if (!m_creg.ReadDWORD(gc_wszValueName_MicDetected, &dwMicDetected))
  1494. {
  1495. // registry key is not present - very odd
  1496. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected key not found in registry");
  1497. hr = DV_HALFDUPLEX;
  1498. goto error_cleanup;
  1499. }
  1500. // Handle bad values from the registry
  1501. if( dwMicDetected > REGVAL_MAXVALID )
  1502. {
  1503. dwMicDetected = REGVAL_NOTRUN;
  1504. }
  1505. switch (dwMicDetected)
  1506. {
  1507. case REGVAL_NOTRUN:
  1508. // Test not run - odd, but pass them for half duplex anyway
  1509. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = 0; test not run");
  1510. hr = DV_HALFDUPLEX;
  1511. goto error_cleanup;
  1512. case REGVAL_CRASHED:
  1513. // test crashed out! This shouldn't happen, since it
  1514. // should have been caught in the full duplex test,
  1515. // but either way, they tried thier best and half
  1516. // duplex worked, so certify them for half duplex.
  1517. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = 1; test crashed");
  1518. hr = DV_HALFDUPLEX;
  1519. goto error_cleanup;
  1520. case REGVAL_FAILED:
  1521. // test failed gracefully - certify for half duplex
  1522. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = 2; test failed gracefully");
  1523. hr = DV_HALFDUPLEX;
  1524. goto error_cleanup;
  1525. case REGVAL_PASSED:
  1526. // test passed
  1527. DPFX(DPFPREP, DVF_INFOLEVEL, "MicDetected = 3; test passed");
  1528. break;
  1529. default:
  1530. // bad key value - odd, but pass them for half duplex anyway.
  1531. DPFX(DPFPREP, DVF_WARNINGLEVEL, "MicDetected = %i; bad key value!", dwMicDetected);
  1532. hr = DV_HALFDUPLEX;
  1533. goto error_cleanup;
  1534. }
  1535. // If we get here, all keys were a clean pass, so return full duplex
  1536. hr = DV_FULLDUPLEX;
  1537. error_cleanup:
  1538. DNLeaveCriticalSection(&m_csLock);
  1539. DPF_EXIT();
  1540. return hr;
  1541. }
  1542. #undef DPF_MODNAME
  1543. #define DPF_MODNAME "CSupervisorInfo::OpenRegKey"
  1544. HRESULT CSupervisorInfo::OpenRegKey(BOOL fCreate)
  1545. {
  1546. DPF_ENTER();
  1547. LONG lRet;
  1548. HRESULT hr;
  1549. CRegistry cregAudioConfig;
  1550. HKEY hkAudioConfig;
  1551. CRegistry cregRender;
  1552. HKEY hkRender;
  1553. WCHAR wszRenderGuidString[GUID_STRING_LEN];
  1554. WCHAR wszCaptureGuidString[GUID_STRING_LEN];
  1555. BOOL bAudioKeyOpen = FALSE;
  1556. BOOL bRenderKeyOpen = FALSE;
  1557. DNEnterCriticalSection(&m_csLock);
  1558. if (!cregAudioConfig.Open(HKEY_CURRENT_USER, gc_wszKeyName_AudioConfig, FALSE, fCreate))
  1559. {
  1560. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Open failed");
  1561. hr = DVERR_GENERIC;
  1562. goto error_cleanup;
  1563. }
  1564. bAudioKeyOpen = TRUE;
  1565. hkAudioConfig = cregAudioConfig.GetHandle();
  1566. if (!cregRender.Open(hkAudioConfig, &m_guidRenderDevice, FALSE, fCreate))
  1567. {
  1568. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Open failed");
  1569. hr = DVERR_GENERIC;
  1570. goto error_cleanup;
  1571. }
  1572. bRenderKeyOpen = TRUE;
  1573. hkRender = cregRender.GetHandle();
  1574. if (!m_creg.Open(hkRender, &m_guidCaptureDevice, FALSE, fCreate))
  1575. {
  1576. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Open failed");
  1577. hr = DVERR_GENERIC;
  1578. goto error_cleanup;
  1579. }
  1580. DNLeaveCriticalSection(&m_csLock);
  1581. DPF_EXIT();
  1582. return S_OK;
  1583. error_cleanup:
  1584. if (bRenderKeyOpen)
  1585. {
  1586. cregRender.Close();
  1587. }
  1588. if (bAudioKeyOpen)
  1589. {
  1590. cregAudioConfig.Close();
  1591. }
  1592. DNLeaveCriticalSection(&m_csLock);
  1593. DPF_EXIT();
  1594. return hr;
  1595. }
  1596. #undef DPF_MODNAME
  1597. #define DPF_MODNAME "CSupervisorInfo::ThereCanBeOnlyOne"
  1598. HRESULT CSupervisorInfo::ThereCanBeOnlyOne()
  1599. {
  1600. DPF_ENTER();
  1601. LONG lRet;
  1602. HANDLE hMutex;
  1603. HRESULT hr;
  1604. hr = DV_OK;
  1605. hMutex = CreateMutex(NULL, FALSE, gc_szMutexName);
  1606. lRet = GetLastError();
  1607. if (hMutex == NULL)
  1608. {
  1609. // something went very wrong
  1610. Diagnostics_Write(DVF_ERRORLEVEL, "CreateMutex failed, code: %i", lRet);
  1611. return DVERR_GENERIC;
  1612. }
  1613. // see if the mutex already existed
  1614. if (lRet == ERROR_ALREADY_EXISTS)
  1615. {
  1616. Diagnostics_Write(DVF_ERRORLEVEL, "Detected another instance of test running");
  1617. if (!CloseHandle(hMutex))
  1618. {
  1619. lRet = GetLastError();
  1620. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  1621. }
  1622. return DVERR_ALREADYPENDING;
  1623. }
  1624. DNEnterCriticalSection(&m_csLock);
  1625. if (m_hMutex != NULL)
  1626. {
  1627. DNLeaveCriticalSection(&m_csLock);
  1628. Diagnostics_Write(DVF_ERRORLEVEL, "m_hMutex not null");
  1629. if (!CloseHandle(hMutex))
  1630. {
  1631. lRet = GetLastError();
  1632. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  1633. }
  1634. return DVERR_GENERIC;
  1635. }
  1636. m_hMutex = hMutex;
  1637. DNLeaveCriticalSection(&m_csLock);
  1638. DPF_EXIT();
  1639. return DV_OK;
  1640. }
  1641. #undef DPF_MODNAME
  1642. #define DPF_MODNAME "CSupervisorInfo::CloseMutex"
  1643. void CSupervisorInfo::CloseMutex()
  1644. {
  1645. DPF_ENTER();
  1646. DNEnterCriticalSection(&m_csLock);
  1647. LONG lRet;
  1648. // close the mutex
  1649. if (!CloseHandle(m_hMutex))
  1650. {
  1651. lRet = GetLastError();
  1652. Diagnostics_Write(DVF_ERRORLEVEL, "CloseHandle failed, code: %i", lRet);
  1653. }
  1654. m_hMutex = NULL;
  1655. DNLeaveCriticalSection(&m_csLock);
  1656. DPF_EXIT();
  1657. return;
  1658. }
  1659. #undef DPF_MODNAME
  1660. #define DPF_MODNAME "CSupervisorInfo::SetVoiceDetected"
  1661. void CSupervisorInfo::SetVoiceDetected()
  1662. {
  1663. DPF_ENTER();
  1664. DNEnterCriticalSection(&m_csLock);
  1665. m_fVoiceDetected = TRUE;
  1666. DNLeaveCriticalSection(&m_csLock);
  1667. DPF_EXIT();
  1668. return;
  1669. }
  1670. #undef DPF_MODNAME
  1671. #define DPF_MODNAME "CSupervisorInfo::ClearVoiceDetected"
  1672. void CSupervisorInfo::ClearVoiceDetected()
  1673. {
  1674. DPF_ENTER();
  1675. DNEnterCriticalSection(&m_csLock);
  1676. m_fVoiceDetected = FALSE;
  1677. DNLeaveCriticalSection(&m_csLock);
  1678. DPF_EXIT();
  1679. return;
  1680. }
  1681. #undef DPF_MODNAME
  1682. #define DPF_MODNAME "CSupervisorInfo::GetVoiceDetected"
  1683. void CSupervisorInfo::GetVoiceDetected(BOOL* lpfPreviousCrash)
  1684. {
  1685. DPF_ENTER();
  1686. DNEnterCriticalSection(&m_csLock);
  1687. *lpfPreviousCrash = m_fVoiceDetected;
  1688. DNLeaveCriticalSection(&m_csLock);
  1689. DPF_EXIT();
  1690. return;
  1691. }
  1692. #undef DPF_MODNAME
  1693. #define DPF_MODNAME "CSupervisorInfo::SetUserBack"
  1694. void CSupervisorInfo::SetUserBack()
  1695. {
  1696. DPF_ENTER();
  1697. DNEnterCriticalSection(&m_csLock);
  1698. m_fUserBack = TRUE;
  1699. DNLeaveCriticalSection(&m_csLock);
  1700. DPF_EXIT();
  1701. return;
  1702. }
  1703. #undef DPF_MODNAME
  1704. #define DPF_MODNAME "CSupervisorInfo::ClearUserBack"
  1705. void CSupervisorInfo::ClearUserBack()
  1706. {
  1707. DPF_ENTER();
  1708. DNEnterCriticalSection(&m_csLock);
  1709. m_fUserBack = FALSE;
  1710. DNLeaveCriticalSection(&m_csLock);
  1711. DPF_EXIT();
  1712. return;
  1713. }
  1714. #undef DPF_MODNAME
  1715. #define DPF_MODNAME "CSupervisorInfo::GetUserBack"
  1716. void CSupervisorInfo::GetUserBack(BOOL* lpfUserBack)
  1717. {
  1718. DPF_ENTER();
  1719. DNEnterCriticalSection(&m_csLock);
  1720. *lpfUserBack = m_fUserBack;
  1721. DNLeaveCriticalSection(&m_csLock);
  1722. DPF_EXIT();
  1723. return;
  1724. }
  1725. #undef DPF_MODNAME
  1726. #define DPF_MODNAME "CSupervisorInfo::SetUserCancel"
  1727. void CSupervisorInfo::SetUserCancel()
  1728. {
  1729. DPF_ENTER();
  1730. DNEnterCriticalSection(&m_csLock);
  1731. m_fUserCancel = TRUE;
  1732. DNLeaveCriticalSection(&m_csLock);
  1733. DPF_EXIT();
  1734. return;
  1735. }
  1736. #undef DPF_MODNAME
  1737. #define DPF_MODNAME "CSupervisorInfo::ClearUserCancel"
  1738. void CSupervisorInfo::ClearUserCancel()
  1739. {
  1740. DPF_ENTER();
  1741. DNEnterCriticalSection(&m_csLock);
  1742. m_fUserCancel = FALSE;
  1743. DNLeaveCriticalSection(&m_csLock);
  1744. DPF_EXIT();
  1745. return;
  1746. }
  1747. #undef DPF_MODNAME
  1748. #define DPF_MODNAME "CSupervisorInfo::GetUserCancel"
  1749. void CSupervisorInfo::GetUserCancel(BOOL* lpfUserCancel)
  1750. {
  1751. DPF_ENTER();
  1752. DNEnterCriticalSection(&m_csLock);
  1753. *lpfUserCancel = m_fUserCancel;
  1754. DNLeaveCriticalSection(&m_csLock);
  1755. DPF_EXIT();
  1756. return;
  1757. }
  1758. #undef DPF_MODNAME
  1759. #define DPF_MODNAME "CSupervisorInfo::SetWelcomeNext"
  1760. void CSupervisorInfo::SetWelcomeNext()
  1761. {
  1762. DPF_ENTER();
  1763. DNEnterCriticalSection(&m_csLock);
  1764. m_fWelcomeNext = TRUE;
  1765. DNLeaveCriticalSection(&m_csLock);
  1766. DPF_EXIT();
  1767. return;
  1768. }
  1769. #undef DPF_MODNAME
  1770. #define DPF_MODNAME "CSupervisorInfo::ClearWelcomeNext"
  1771. void CSupervisorInfo::ClearWelcomeNext()
  1772. {
  1773. DPF_ENTER();
  1774. DNEnterCriticalSection(&m_csLock);
  1775. m_fWelcomeNext = FALSE;
  1776. DNLeaveCriticalSection(&m_csLock);
  1777. DPF_EXIT();
  1778. return;
  1779. }
  1780. #undef DPF_MODNAME
  1781. #define DPF_MODNAME "CSupervisorInfo::GetWelcomeNext"
  1782. void CSupervisorInfo::GetWelcomeNext(BOOL* lpfWelcomeNext)
  1783. {
  1784. DPF_ENTER();
  1785. DNEnterCriticalSection(&m_csLock);
  1786. *lpfWelcomeNext = m_fWelcomeNext;
  1787. DNLeaveCriticalSection(&m_csLock);
  1788. DPF_EXIT();
  1789. return;
  1790. }
  1791. #undef DPF_MODNAME
  1792. #define DPF_MODNAME "CSupervisorInfo::GetError"
  1793. void CSupervisorInfo::GetError(HRESULT* hr)
  1794. {
  1795. DPF_ENTER();
  1796. DNEnterCriticalSection(&m_csLock);
  1797. *hr = m_hrError;
  1798. DNLeaveCriticalSection(&m_csLock);
  1799. DPF_EXIT();
  1800. return;
  1801. }
  1802. #undef DPF_MODNAME
  1803. #define DPF_MODNAME "CSupervisorInfo::SetError"
  1804. void CSupervisorInfo::SetError(HRESULT hr)
  1805. {
  1806. DPF_ENTER();
  1807. DNEnterCriticalSection(&m_csLock);
  1808. m_hrError = hr;
  1809. DNLeaveCriticalSection(&m_csLock);
  1810. DPF_EXIT();
  1811. return;
  1812. }
  1813. #undef DPF_MODNAME
  1814. #define DPF_MODNAME "CSupervisorInfo::GetTitleFont"
  1815. void CSupervisorInfo::GetTitleFont(HFONT* lphfTitle)
  1816. {
  1817. DPF_ENTER();
  1818. DNEnterCriticalSection(&m_csLock);
  1819. *lphfTitle = m_hfTitle;
  1820. DNLeaveCriticalSection(&m_csLock);
  1821. DPF_EXIT();
  1822. return;
  1823. }
  1824. #undef DPF_MODNAME
  1825. #define DPF_MODNAME "CSupervisorInfo::GetBoldFont"
  1826. void CSupervisorInfo::GetBoldFont(HFONT* lphfBold)
  1827. {
  1828. DPF_ENTER();
  1829. DNEnterCriticalSection(&m_csLock);
  1830. *lphfBold = m_hfBold;
  1831. DNLeaveCriticalSection(&m_csLock);
  1832. DPF_EXIT();
  1833. return;
  1834. }
  1835. #undef DPF_MODNAME
  1836. #define DPF_MODNAME "CSupervisorInfo::GetCaptureDevice"
  1837. void CSupervisorInfo::GetCaptureDevice(GUID* lpguidCaptureDevice)
  1838. {
  1839. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter");
  1840. DNEnterCriticalSection(&m_csLock);
  1841. *lpguidCaptureDevice = m_guidCaptureDevice;
  1842. DNLeaveCriticalSection(&m_csLock);
  1843. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Exit");
  1844. return;
  1845. }
  1846. #undef DPF_MODNAME
  1847. #define DPF_MODNAME "CSupervisorInfo::SetCaptureDevice"
  1848. void CSupervisorInfo::SetCaptureDevice(const GUID& guidCaptureDevice)
  1849. {
  1850. DPF_ENTER();
  1851. DNEnterCriticalSection(&m_csLock);
  1852. m_guidCaptureDevice = guidCaptureDevice;
  1853. DNLeaveCriticalSection(&m_csLock);
  1854. DPF_EXIT();
  1855. return;
  1856. }
  1857. #undef DPF_MODNAME
  1858. #define DPF_MODNAME "CSupervisorInfo::GetRenderDevice"
  1859. void CSupervisorInfo::GetRenderDevice(GUID* lpguidRenderDevice)
  1860. {
  1861. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Enter");
  1862. DNEnterCriticalSection(&m_csLock);
  1863. *lpguidRenderDevice = m_guidRenderDevice;
  1864. DNLeaveCriticalSection(&m_csLock);
  1865. DPFX(DPFPREP, DVF_ENTRYLEVEL, "Exit");
  1866. return;
  1867. }
  1868. #undef DPF_MODNAME
  1869. #define DPF_MODNAME "CSupervisorInfo::SetRenderDevice"
  1870. void CSupervisorInfo::SetRenderDevice(const GUID& guidRenderDevice)
  1871. {
  1872. DPF_ENTER();
  1873. DNEnterCriticalSection(&m_csLock);
  1874. m_guidRenderDevice = guidRenderDevice;
  1875. DNLeaveCriticalSection(&m_csLock);
  1876. DPF_EXIT();
  1877. return;
  1878. }
  1879. #undef DPF_MODNAME
  1880. #define DPF_MODNAME "CSupervisorInfo::SetWaveOutId"
  1881. HRESULT CSupervisorInfo::SetWaveOutId(UINT ui)
  1882. {
  1883. HRESULT hr = DV_OK;
  1884. DPF_ENTER();
  1885. DNEnterCriticalSection(&m_csLock);
  1886. m_uiWaveOutDeviceId = ui;
  1887. ZeroMemory(&m_woCaps, sizeof(WAVEOUTCAPS));
  1888. MMRESULT mmr = waveOutGetDevCaps(ui, &m_woCaps, sizeof(WAVEOUTCAPS));
  1889. if (mmr != MMSYSERR_NOERROR)
  1890. {
  1891. ZeroMemory(&m_woCaps, sizeof(WAVEOUTCAPS));
  1892. hr = DVERR_INVALIDPARAM;
  1893. }
  1894. //error_cleanup:
  1895. DNLeaveCriticalSection(&m_csLock);
  1896. DPF_EXIT();
  1897. return hr;
  1898. }
  1899. #undef DPF_MODNAME
  1900. #define DPF_MODNAME "CSupervisorInfo::SetWaveInId"
  1901. void CSupervisorInfo::SetWaveInId(UINT ui)
  1902. {
  1903. DPF_ENTER();
  1904. DNEnterCriticalSection(&m_csLock);
  1905. m_uiWaveInDeviceId = ui;
  1906. DNLeaveCriticalSection(&m_csLock);
  1907. DPF_EXIT();
  1908. return;
  1909. }
  1910. #undef DPF_MODNAME
  1911. #define DPF_MODNAME "CSupervisorInfo::GetLoopbackFlags"
  1912. void CSupervisorInfo::GetLoopbackFlags(DWORD* pdwFlags)
  1913. {
  1914. DPF_ENTER();
  1915. DNEnterCriticalSection(&m_csLock);
  1916. *pdwFlags = m_dwLoopbackFlags;
  1917. DNLeaveCriticalSection(&m_csLock);
  1918. DPF_EXIT();
  1919. return;
  1920. }
  1921. #undef DPF_MODNAME
  1922. #define DPF_MODNAME "CSupervisorInfo::SetLoopbackFlags"
  1923. void CSupervisorInfo::SetLoopbackFlags(DWORD dwFlags)
  1924. {
  1925. DPF_ENTER();
  1926. DNEnterCriticalSection(&m_csLock);
  1927. m_dwLoopbackFlags = dwFlags;
  1928. DNLeaveCriticalSection(&m_csLock);
  1929. DPF_EXIT();
  1930. return;
  1931. }
  1932. #undef DPF_MODNAME
  1933. #define DPF_MODNAME "CSupervisorInfo::GetCheckAudioSetupFlags"
  1934. void CSupervisorInfo::GetCheckAudioSetupFlags(DWORD* pdwFlags)
  1935. {
  1936. DPF_ENTER();
  1937. DNEnterCriticalSection(&m_csLock);
  1938. *pdwFlags = m_dwCheckAudioSetupFlags;
  1939. DNLeaveCriticalSection(&m_csLock);
  1940. DPF_EXIT();
  1941. return;
  1942. }
  1943. #undef DPF_MODNAME
  1944. #define DPF_MODNAME "CSupervisorInfo::SetCheckAudioSetupFlags"
  1945. void CSupervisorInfo::SetCheckAudioSetupFlags(DWORD dwFlags)
  1946. {
  1947. DPF_ENTER();
  1948. DNEnterCriticalSection(&m_csLock);
  1949. m_dwCheckAudioSetupFlags = dwFlags;
  1950. DNLeaveCriticalSection(&m_csLock);
  1951. DPF_EXIT();
  1952. return;
  1953. }
  1954. #undef DPF_MODNAME
  1955. #define DPF_MODNAME "CSupervisorInfo::GetFullDuplexResults"
  1956. void CSupervisorInfo::GetFullDuplexResults(HRESULT* phr)
  1957. {
  1958. DPF_ENTER();
  1959. DNEnterCriticalSection(&m_csLock);
  1960. *phr = m_hrFullDuplexResults;
  1961. DNLeaveCriticalSection(&m_csLock);
  1962. DPF_EXIT();
  1963. return;
  1964. }
  1965. #undef DPF_MODNAME
  1966. #define DPF_MODNAME "CSupervisorInfo::SetFullDuplexResults"
  1967. void CSupervisorInfo::SetFullDuplexResults(HRESULT hr)
  1968. {
  1969. DPF_ENTER();
  1970. DNEnterCriticalSection(&m_csLock);
  1971. m_hrFullDuplexResults = hr;
  1972. DNLeaveCriticalSection(&m_csLock);
  1973. DPF_EXIT();
  1974. return;
  1975. }
  1976. #undef DPF_MODNAME
  1977. #define DPF_MODNAME "CSupervisorInfo::GetHWNDParent"
  1978. void CSupervisorInfo::GetHWNDParent(HWND* lphwnd)
  1979. {
  1980. DPF_ENTER();
  1981. DNEnterCriticalSection(&m_csLock);
  1982. *lphwnd = m_hwndParent;
  1983. DNLeaveCriticalSection(&m_csLock);
  1984. DPF_EXIT();
  1985. return;
  1986. }
  1987. #undef DPF_MODNAME
  1988. #define DPF_MODNAME "CSupervisorInfo::SetHWNDWizard"
  1989. void CSupervisorInfo::SetHWNDParent(HWND hwnd)
  1990. {
  1991. DPF_ENTER();
  1992. DNEnterCriticalSection(&m_csLock);
  1993. m_hwndParent = hwnd;
  1994. DNLeaveCriticalSection(&m_csLock);
  1995. DPF_EXIT();
  1996. return;
  1997. }
  1998. #undef DPF_MODNAME
  1999. #define DPF_MODNAME "CSupervisorInfo::GetHWNDWizard"
  2000. void CSupervisorInfo::GetHWNDWizard(HWND* lphwnd)
  2001. {
  2002. DPF_ENTER();
  2003. DNEnterCriticalSection(&m_csLock);
  2004. *lphwnd = m_hwndWizard;
  2005. DNLeaveCriticalSection(&m_csLock);
  2006. DPF_EXIT();
  2007. return;
  2008. }
  2009. #undef DPF_MODNAME
  2010. #define DPF_MODNAME "CSupervisorInfo::SetHWNDWizard"
  2011. void CSupervisorInfo::SetHWNDWizard(HWND hwnd)
  2012. {
  2013. DPF_ENTER();
  2014. DNEnterCriticalSection(&m_csLock);
  2015. m_hwndWizard = hwnd;
  2016. DNLeaveCriticalSection(&m_csLock);
  2017. DPF_EXIT();
  2018. return;
  2019. }
  2020. #undef DPF_MODNAME
  2021. #define DPF_MODNAME "CSupervisorInfo::GetHWNDDialog"
  2022. void CSupervisorInfo::GetHWNDDialog(HWND* lphwnd)
  2023. {
  2024. DPF_ENTER();
  2025. DNEnterCriticalSection(&m_csLock);
  2026. *lphwnd = m_hwndDialog;
  2027. DNLeaveCriticalSection(&m_csLock);
  2028. DPF_EXIT();
  2029. return;
  2030. }
  2031. #undef DPF_MODNAME
  2032. #define DPF_MODNAME "CSupervisorInfo::SetHWNDDialog"
  2033. void CSupervisorInfo::SetHWNDDialog(HWND hwnd)
  2034. {
  2035. DPF_ENTER();
  2036. DNEnterCriticalSection(&m_csLock);
  2037. m_hwndDialog = hwnd;
  2038. DNLeaveCriticalSection(&m_csLock);
  2039. DPF_EXIT();
  2040. return;
  2041. }
  2042. #undef DPF_MODNAME
  2043. #define DPF_MODNAME "CSupervisorInfo::GetHWNDProgress"
  2044. void CSupervisorInfo::GetHWNDProgress(HWND* lphwnd)
  2045. {
  2046. DPF_ENTER();
  2047. DNEnterCriticalSection(&m_csLock);
  2048. *lphwnd = m_hwndProgress;
  2049. DNLeaveCriticalSection(&m_csLock);
  2050. DPF_EXIT();
  2051. return;
  2052. }
  2053. #undef DPF_MODNAME
  2054. #define DPF_MODNAME "CSupervisorInfo::SetHWNDProgress"
  2055. void CSupervisorInfo::SetHWNDProgress(HWND hwnd)
  2056. {
  2057. DPF_ENTER();
  2058. DNEnterCriticalSection(&m_csLock);
  2059. m_hwndProgress = hwnd;
  2060. DNLeaveCriticalSection(&m_csLock);
  2061. DPF_EXIT();
  2062. return;
  2063. }
  2064. #undef DPF_MODNAME
  2065. #define DPF_MODNAME "CSupervisorInfo::GetHWNDInputPeak"
  2066. void CSupervisorInfo::GetHWNDInputPeak(HWND* lphwnd)
  2067. {
  2068. DPF_ENTER();
  2069. DNEnterCriticalSection(&m_csLock);
  2070. *lphwnd = m_hwndInputPeak;
  2071. DNLeaveCriticalSection(&m_csLock);
  2072. DPF_EXIT();
  2073. return;
  2074. }
  2075. #undef DPF_MODNAME
  2076. #define DPF_MODNAME "CSupervisorInfo::SetHWNDInputPeak"
  2077. void CSupervisorInfo::SetHWNDInputPeak(HWND hwnd)
  2078. {
  2079. DPF_ENTER();
  2080. DNEnterCriticalSection(&m_csLock);
  2081. m_hwndInputPeak = hwnd;
  2082. DNLeaveCriticalSection(&m_csLock);
  2083. DPF_EXIT();
  2084. return;
  2085. }
  2086. #undef DPF_MODNAME
  2087. #define DPF_MODNAME "CSupervisorInfo::GetHWNDOutputPeak"
  2088. void CSupervisorInfo::GetHWNDOutputPeak(HWND* lphwnd)
  2089. {
  2090. DPF_ENTER();
  2091. DNEnterCriticalSection(&m_csLock);
  2092. *lphwnd = m_hwndOutputPeak;
  2093. DNLeaveCriticalSection(&m_csLock);
  2094. DPF_EXIT();
  2095. return;
  2096. }
  2097. #undef DPF_MODNAME
  2098. #define DPF_MODNAME "CSupervisorInfo::SetHWNDOutputPeak"
  2099. void CSupervisorInfo::SetHWNDOutputPeak(HWND hwnd)
  2100. {
  2101. DPF_ENTER();
  2102. DNEnterCriticalSection(&m_csLock);
  2103. m_hwndOutputPeak = hwnd;
  2104. DNLeaveCriticalSection(&m_csLock);
  2105. DPF_EXIT();
  2106. return;
  2107. }
  2108. #undef DPF_MODNAME
  2109. #define DPF_MODNAME "CSupervisorInfo::GetHWNDInputVolumeSlider"
  2110. void CSupervisorInfo::GetHWNDInputVolumeSlider(HWND* lphwnd)
  2111. {
  2112. DPF_ENTER();
  2113. DNEnterCriticalSection(&m_csLock);
  2114. *lphwnd = m_hwndInputVolumeSlider;
  2115. DNLeaveCriticalSection(&m_csLock);
  2116. DPF_EXIT();
  2117. return;
  2118. }
  2119. #undef DPF_MODNAME
  2120. #define DPF_MODNAME "CSupervisorInfo::SetHWNDInputVolumeSlider"
  2121. void CSupervisorInfo::SetHWNDInputVolumeSlider(HWND hwnd)
  2122. {
  2123. DPF_ENTER();
  2124. DNEnterCriticalSection(&m_csLock);
  2125. m_hwndInputVolumeSlider = hwnd;
  2126. DNLeaveCriticalSection(&m_csLock);
  2127. DPF_EXIT();
  2128. return;
  2129. }
  2130. #undef DPF_MODNAME
  2131. #define DPF_MODNAME "CSupervisorInfo::GetInputVolumeSliderPos"
  2132. void CSupervisorInfo::GetInputVolumeSliderPos(LONG* lpl)
  2133. {
  2134. DPF_ENTER();
  2135. DNEnterCriticalSection(&m_csLock);
  2136. *lpl = m_lInputVolumeSliderPos;
  2137. DNLeaveCriticalSection(&m_csLock);
  2138. DPF_EXIT();
  2139. return;
  2140. }
  2141. #undef DPF_MODNAME
  2142. #define DPF_MODNAME "CSupervisorInfo::SetInputVolumeSliderPos"
  2143. void CSupervisorInfo::SetInputVolumeSliderPos(LONG l)
  2144. {
  2145. DPF_ENTER();
  2146. DNEnterCriticalSection(&m_csLock);
  2147. m_lInputVolumeSliderPos = l;
  2148. DNLeaveCriticalSection(&m_csLock);
  2149. DPF_EXIT();
  2150. return;
  2151. }
  2152. #undef DPF_MODNAME
  2153. #define DPF_MODNAME "CSupervisorInfo::GetHWNDOutputVolumeSlider"
  2154. void CSupervisorInfo::GetHWNDOutputVolumeSlider(HWND* lphwnd)
  2155. {
  2156. DPF_ENTER();
  2157. DNEnterCriticalSection(&m_csLock);
  2158. *lphwnd = m_hwndOutputVolumeSlider;
  2159. DNLeaveCriticalSection(&m_csLock);
  2160. DPF_EXIT();
  2161. return;
  2162. }
  2163. #undef DPF_MODNAME
  2164. #define DPF_MODNAME "CSupervisorInfo::SetHWNDOutputVolumeSlider"
  2165. void CSupervisorInfo::SetHWNDOutputVolumeSlider(HWND hwnd)
  2166. {
  2167. DPF_ENTER();
  2168. DNEnterCriticalSection(&m_csLock);
  2169. m_hwndOutputVolumeSlider = hwnd;
  2170. DNLeaveCriticalSection(&m_csLock);
  2171. DPF_EXIT();
  2172. return;
  2173. }
  2174. #undef DPF_MODNAME
  2175. #define DPF_MODNAME "CSupervisorInfo::GetDPVC"
  2176. void CSupervisorInfo::GetDPVC(LPDIRECTPLAYVOICECLIENT* lplpdpvc)
  2177. {
  2178. DPF_ENTER();
  2179. DNEnterCriticalSection(&m_csLock);
  2180. *lplpdpvc = m_lpdpvc;
  2181. DNLeaveCriticalSection(&m_csLock);
  2182. DPF_EXIT();
  2183. return;
  2184. }
  2185. #undef DPF_MODNAME
  2186. #define DPF_MODNAME "CSupervisorInfo::SetDPVC"
  2187. void CSupervisorInfo::SetDPVC(LPDIRECTPLAYVOICECLIENT lpdpvc)
  2188. {
  2189. DPF_ENTER();
  2190. DNEnterCriticalSection(&m_csLock);
  2191. m_lpdpvc = lpdpvc;
  2192. DNLeaveCriticalSection(&m_csLock);
  2193. DPF_EXIT();
  2194. return;
  2195. }
  2196. #undef DPF_MODNAME
  2197. #define DPF_MODNAME "CSupervisorInfo::GetLoopbackShutdownEvent"
  2198. void CSupervisorInfo::GetLoopbackShutdownEvent(HANDLE* lphEvent)
  2199. {
  2200. DPF_ENTER();
  2201. DNEnterCriticalSection(&m_csLock);
  2202. *lphEvent = m_hLoopbackShutdownEvent;
  2203. DNLeaveCriticalSection(&m_csLock);
  2204. DPF_EXIT();
  2205. return;
  2206. }
  2207. #undef DPF_MODNAME
  2208. #define DPF_MODNAME "CSupervisorInfo::SetLoopbackShutdownEvent"
  2209. void CSupervisorInfo::SetLoopbackShutdownEvent(HANDLE hEvent)
  2210. {
  2211. DPF_ENTER();
  2212. DNEnterCriticalSection(&m_csLock);
  2213. m_hLoopbackShutdownEvent = hEvent;
  2214. DNLeaveCriticalSection(&m_csLock);
  2215. DPF_EXIT();
  2216. return;
  2217. }
  2218. #undef DPF_MODNAME
  2219. #define DPF_MODNAME "CSupervisorInfo::GetIPC"
  2220. void CSupervisorInfo::GetIPC(CSupervisorIPC** lplpsipc)
  2221. {
  2222. DPF_ENTER();
  2223. DNEnterCriticalSection(&m_csLock);
  2224. *lplpsipc = &m_sipc;
  2225. DNLeaveCriticalSection(&m_csLock);
  2226. DPF_EXIT();
  2227. return;
  2228. }
  2229. #undef DPF_MODNAME
  2230. #define DPF_MODNAME "CSupervisorInfo::GetAbortFullDuplex"
  2231. void CSupervisorInfo::GetAbortFullDuplex(BOOL* lpfAbort)
  2232. {
  2233. DPF_ENTER();
  2234. DNEnterCriticalSection(&m_csLock);
  2235. *lpfAbort = m_fAbortFullDuplex;
  2236. DNLeaveCriticalSection(&m_csLock);
  2237. DPF_EXIT();
  2238. return;
  2239. }
  2240. #undef DPF_MODNAME
  2241. #define DPF_MODNAME "CSupervisorInfo::ClearAbortFullDuplex"
  2242. void CSupervisorInfo::ClearAbortFullDuplex()
  2243. {
  2244. DPF_ENTER();
  2245. DNEnterCriticalSection(&m_csLock);
  2246. m_fAbortFullDuplex = FALSE;
  2247. DNLeaveCriticalSection(&m_csLock);
  2248. DPF_EXIT();
  2249. return;
  2250. }
  2251. #undef DPF_MODNAME
  2252. #define DPF_MODNAME "CSupervisorInfo::InitIPC"
  2253. HRESULT CSupervisorInfo::InitIPC()
  2254. {
  2255. DPF_ENTER();
  2256. HRESULT hr;
  2257. // the IPC object has it's own guard...
  2258. hr = m_sipc.Init();
  2259. DPF_EXIT();
  2260. return hr;
  2261. }
  2262. #undef DPF_MODNAME
  2263. #define DPF_MODNAME "CSupervisorInfo::DeinitIPC"
  2264. HRESULT CSupervisorInfo::DeinitIPC()
  2265. {
  2266. DPF_ENTER();
  2267. HRESULT hr;
  2268. // The IPC object has it's own guard...
  2269. // and this is a safe call even if Init
  2270. // has not been called
  2271. hr = m_sipc.Deinit();
  2272. DPF_EXIT();
  2273. return hr;
  2274. }
  2275. #undef DPF_MODNAME
  2276. #define DPF_MODNAME "CSupervisorInfo::InitClass"
  2277. BOOL CSupervisorInfo::InitClass()
  2278. {
  2279. if (DNInitializeCriticalSection(&m_csLock))
  2280. {
  2281. m_fCritSecInited = TRUE;
  2282. return TRUE;
  2283. }
  2284. else
  2285. {
  2286. return FALSE;
  2287. }
  2288. }
  2289. #undef DPF_MODNAME
  2290. #define DPF_MODNAME "SupervisorCheckAudioSetup"
  2291. HRESULT SupervisorCheckAudioSetup(
  2292. const GUID* lpguidRenderDevice,
  2293. const GUID* lpguidCaptureDevice,
  2294. HWND hwndParent,
  2295. DWORD dwFlags)
  2296. {
  2297. DPF_ENTER();
  2298. HRESULT hr;
  2299. LRESULT lRet;
  2300. HKEY hkDevice = NULL;
  2301. int iRet;
  2302. CSupervisorInfo sinfo;
  2303. CPeakMeterWndClass pmwc;
  2304. BOOL fFullDuplexPassed;
  2305. BOOL fVoiceDetected;
  2306. BOOL fUserCancel;
  2307. BOOL fUserBack;
  2308. GUID guidCaptureDevice;
  2309. GUID guidRenderDevice;
  2310. BOOL fRegKeyOpen = FALSE;
  2311. BOOL fWndClassRegistered = FALSE;
  2312. BOOL fTitleFontCreated = FALSE;
  2313. BOOL fBoldFontCreated = FALSE;
  2314. BOOL fMutexOpen = FALSE;
  2315. if (!sinfo.InitClass())
  2316. {
  2317. return DVERR_OUTOFMEMORY;
  2318. }
  2319. // init the globals
  2320. g_hResDLLInstance = NULL;
  2321. // validate the HWND, if non null
  2322. if (hwndParent != NULL && !IsWindow(hwndParent))
  2323. {
  2324. Diagnostics_Write(DVF_ERRORLEVEL, "Invalid (but non-null) Window Handle passed in CheckAudioSetup");
  2325. hr = DVERR_INVALIDPARAM;
  2326. goto error_cleanup;
  2327. }
  2328. // validate the flags
  2329. if (dwFlags & ~(DVFLAGS_QUERYONLY|DVFLAGS_NOQUERY|DVFLAGS_WAVEIDS|DVFLAGS_ALLOWBACK))
  2330. {
  2331. Diagnostics_Write(DVF_ERRORLEVEL, "Invalid flags specified in CheckAudioSetup: %x", dwFlags);
  2332. hr = DVERR_INVALIDFLAGS;
  2333. goto error_cleanup;
  2334. }
  2335. if (dwFlags & DVFLAGS_QUERYONLY)
  2336. {
  2337. if (dwFlags & (DVFLAGS_NOQUERY|DVFLAGS_ALLOWBACK))
  2338. {
  2339. Diagnostics_Write(DVF_ERRORLEVEL, "Invalid flags specified in CheckAudioSetup: %x", dwFlags);
  2340. hr = DVERR_INVALIDFLAGS;
  2341. goto error_cleanup;
  2342. }
  2343. }
  2344. // save the flags
  2345. sinfo.SetCheckAudioSetupFlags(dwFlags);
  2346. // if the waveid flag was specified, translate the waveid to a guid
  2347. if (dwFlags & DVFLAGS_WAVEIDS)
  2348. {
  2349. hr = DV_MapWaveIDToGUID( FALSE, lpguidRenderDevice->Data1, guidRenderDevice );
  2350. if (FAILED(hr))
  2351. {
  2352. Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapWaveIDToGUID failed, code: %i", hr);
  2353. goto error_cleanup;
  2354. }
  2355. hr = DV_MapWaveIDToGUID( TRUE, lpguidCaptureDevice->Data1, guidCaptureDevice );
  2356. if (FAILED(hr))
  2357. {
  2358. Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapWaveIDToGUID failed, code: %i", hr);
  2359. goto error_cleanup;
  2360. }
  2361. }
  2362. else
  2363. {
  2364. hr = DV_MapPlaybackDevice(lpguidRenderDevice, &guidRenderDevice);
  2365. if (FAILED(hr))
  2366. {
  2367. Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapPlaybackDevice failed, code: %i", hr);
  2368. goto error_cleanup;
  2369. }
  2370. // map the devices
  2371. hr = DV_MapCaptureDevice(lpguidCaptureDevice, &guidCaptureDevice);
  2372. if (FAILED(hr))
  2373. {
  2374. Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapCaptureDevice failed, code: %i", hr);
  2375. goto error_cleanup;
  2376. }
  2377. }
  2378. // the device guids have been mapped, if required, so save them
  2379. sinfo.SetCaptureDevice(guidCaptureDevice);
  2380. sinfo.SetRenderDevice(guidRenderDevice);
  2381. // get the device descriptions, which also validates the GUIDs on
  2382. // pre-millennium systems.
  2383. hr = sinfo.GetDeviceDescriptions();
  2384. if (FAILED(hr))
  2385. {
  2386. // error, log it and bail out of the wizard
  2387. Diagnostics_Write(DVF_ERRORLEVEL, "Error getting device descriptions, code: %i", hr);
  2388. goto error_cleanup;
  2389. }
  2390. // Open the registry key
  2391. hr = sinfo.OpenRegKey(TRUE);
  2392. if (FAILED(hr))
  2393. {
  2394. // error, log it and bail out of the wizard
  2395. Diagnostics_Write(DVF_ERRORLEVEL, "Unable to open reg key, code: %i", hr);
  2396. hr = DVERR_GENERIC;
  2397. goto error_cleanup;
  2398. }
  2399. fRegKeyOpen = TRUE;
  2400. if (dwFlags & DVFLAGS_QUERYONLY)
  2401. {
  2402. hr = SupervisorQueryAudioSetup(&sinfo);
  2403. sinfo.CloseRegKey();
  2404. DPF_EXIT();
  2405. return hr;
  2406. }
  2407. g_hResDLLInstance = LoadLibraryA(gc_szResDLLName);
  2408. if (g_hResDLLInstance == NULL)
  2409. {
  2410. lRet = GetLastError();
  2411. Diagnostics_Write(DVF_ERRORLEVEL, "Unable to get instance handle to resource dll: %hs", gc_szResDLLName);
  2412. Diagnostics_Write(DVF_ERRORLEVEL, "LoadLibrary error code: %i", lRet);
  2413. hr = DVERR_GENERIC;
  2414. goto error_cleanup;
  2415. }
  2416. // check for other instances of the wizard
  2417. hr = sinfo.ThereCanBeOnlyOne();
  2418. if (FAILED(hr))
  2419. {
  2420. if (hr == DVERR_ALREADYPENDING)
  2421. {
  2422. Diagnostics_Write(DVF_ERRORLEVEL, "DirectPlay Voice Setup Wizard already running");
  2423. }
  2424. else
  2425. {
  2426. Diagnostics_Write(DVF_ERRORLEVEL, "ThereCanBeOnlyOne failed, hr: %i", hr);
  2427. }
  2428. goto error_cleanup;
  2429. }
  2430. fMutexOpen = TRUE;
  2431. // register the peak meter custom control window class
  2432. hr = pmwc.Register();
  2433. if (FAILED(hr))
  2434. {
  2435. Diagnostics_Write(DVF_ERRORLEVEL, "CPeakMeterWndClass::Init failed, code: %i", hr);
  2436. goto error_cleanup;
  2437. }
  2438. fWndClassRegistered = TRUE;
  2439. // create the wizard header fonts
  2440. hr = sinfo.CreateTitleFont();
  2441. if (FAILED(hr))
  2442. {
  2443. Diagnostics_Write(DVF_ERRORLEVEL, "CreateTitleFont failed");
  2444. goto error_cleanup;
  2445. }
  2446. fTitleFontCreated = TRUE;
  2447. hr = sinfo.CreateBoldFont();
  2448. if (FAILED(hr))
  2449. {
  2450. Diagnostics_Write(DVF_ERRORLEVEL, "CreateBoldFont failed");
  2451. goto error_cleanup;
  2452. }
  2453. fBoldFontCreated = TRUE;
  2454. // prepare the wizard pages
  2455. PROPSHEETPAGE psp;
  2456. HPROPSHEETPAGE rghpsp[10];
  2457. PROPSHEETHEADER psh;
  2458. // Welcome page
  2459. ZeroMemory(&psp, sizeof(psp));
  2460. // psp.dwSize = sizeof(psp);
  2461. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2462. psp.dwFlags = PSP_DEFAULT; //|PSP_HIDEHEADER;
  2463. psp.hInstance = g_hResDLLInstance;
  2464. psp.lParam = (LPARAM) &sinfo;
  2465. psp.pfnDlgProc = WelcomeProc;
  2466. psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOME);
  2467. rghpsp[0] = CreatePropertySheetPage(&psp);
  2468. if (rghpsp[0] == NULL)
  2469. {
  2470. lRet = GetLastError();
  2471. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2472. hr = DVERR_GENERIC;
  2473. goto error_cleanup;
  2474. }
  2475. // Full Duplex Test Page
  2476. ZeroMemory(&psp, sizeof(psp));
  2477. // psp.dwSize = sizeof(psp);
  2478. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2479. psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER;
  2480. psp.hInstance = g_hResDLLInstance;
  2481. psp.lParam = (LPARAM) &sinfo;
  2482. psp.pfnDlgProc = FullDuplexProc;
  2483. psp.pszTemplate = MAKEINTRESOURCE(IDD_FULLDUPLEXTEST);
  2484. rghpsp[1] = CreatePropertySheetPage(&psp);
  2485. if (rghpsp[1] == NULL)
  2486. {
  2487. lRet = GetLastError();
  2488. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2489. hr = DVERR_GENERIC;
  2490. goto error_cleanup;
  2491. }
  2492. // Microphone Test Page
  2493. ZeroMemory(&psp, sizeof(psp));
  2494. // psp.dwSize = sizeof(psp);
  2495. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2496. psp.dwFlags = PSP_DEFAULT; //|PSP_HIDEHEADER;
  2497. psp.hInstance = g_hResDLLInstance;
  2498. psp.lParam = (LPARAM) &sinfo;
  2499. psp.pfnDlgProc = MicTestProc;
  2500. psp.pszTemplate = MAKEINTRESOURCE(IDD_MICTEST);
  2501. rghpsp[2] = CreatePropertySheetPage(&psp);
  2502. if (rghpsp[2] == NULL)
  2503. {
  2504. lRet = GetLastError();
  2505. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2506. hr = DVERR_GENERIC;
  2507. goto error_cleanup;
  2508. }
  2509. // Microphone Failed Page
  2510. ZeroMemory(&psp, sizeof(psp));
  2511. // psp.dwSize = sizeof(psp);
  2512. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2513. psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER;
  2514. psp.hInstance = g_hResDLLInstance;
  2515. psp.lParam = (LPARAM) &sinfo;
  2516. psp.pfnDlgProc = MicTestFailedProc;
  2517. psp.pszTemplate = MAKEINTRESOURCE(IDD_MICTEST_FAILED);
  2518. rghpsp[3] = CreatePropertySheetPage(&psp);
  2519. if (rghpsp[3] == NULL)
  2520. {
  2521. lRet = GetLastError();
  2522. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2523. hr = DVERR_GENERIC;
  2524. goto error_cleanup;
  2525. }
  2526. // Speaker Test Page
  2527. ZeroMemory(&psp, sizeof(psp));
  2528. // psp.dwSize = sizeof(psp);
  2529. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2530. psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER;
  2531. psp.hInstance = g_hResDLLInstance;
  2532. psp.lParam = (LPARAM) &sinfo;
  2533. psp.pfnDlgProc = SpeakerTestProc;
  2534. psp.pszTemplate = MAKEINTRESOURCE(IDD_SPEAKER_TEST);
  2535. rghpsp[4] = CreatePropertySheetPage(&psp);
  2536. if (rghpsp[4] == NULL)
  2537. {
  2538. lRet = GetLastError();
  2539. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2540. hr = DVERR_GENERIC;
  2541. goto error_cleanup;
  2542. }
  2543. // Wizard Complete Page
  2544. ZeroMemory(&psp, sizeof(psp));
  2545. // psp.dwSize = sizeof(psp);
  2546. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2547. psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER;
  2548. psp.hInstance = g_hResDLLInstance;
  2549. psp.lParam = (LPARAM) &sinfo;
  2550. psp.pfnDlgProc = CompleteProc;
  2551. psp.pszTemplate = MAKEINTRESOURCE(IDD_COMPLETE);
  2552. rghpsp[5] = CreatePropertySheetPage(&psp);
  2553. if (rghpsp[5] == NULL)
  2554. {
  2555. lRet = GetLastError();
  2556. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2557. hr = DVERR_GENERIC;
  2558. goto error_cleanup;
  2559. }
  2560. // half duplex failed page
  2561. ZeroMemory(&psp, sizeof(psp));
  2562. // psp.dwSize = sizeof(psp);
  2563. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2564. psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER;
  2565. psp.hInstance = g_hResDLLInstance;
  2566. psp.lParam = (LPARAM) &sinfo;
  2567. psp.pfnDlgProc = HalfDuplexFailedProc;
  2568. psp.pszTemplate = MAKEINTRESOURCE(IDD_HALFDUPLEXFAILED);
  2569. rghpsp[6] = CreatePropertySheetPage(&psp);
  2570. if (rghpsp[6] == NULL)
  2571. {
  2572. lRet = GetLastError();
  2573. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2574. hr = DVERR_GENERIC;
  2575. goto error_cleanup;
  2576. }
  2577. // Full duplex failed page
  2578. ZeroMemory(&psp, sizeof(psp));
  2579. // psp.dwSize = sizeof(psp);
  2580. psp.dwSize = PROPSHEETPAGE_STRUCT_SIZE;
  2581. psp.dwFlags = PSP_DEFAULT;//|PSP_HIDEHEADER;
  2582. psp.hInstance = g_hResDLLInstance;
  2583. psp.lParam = (LPARAM) &sinfo;
  2584. psp.pfnDlgProc = FullDuplexFailedProc;
  2585. psp.pszTemplate = MAKEINTRESOURCE(IDD_FULLDUPLEXFAILED);
  2586. rghpsp[7] = CreatePropertySheetPage(&psp);
  2587. if (rghpsp[7] == NULL)
  2588. {
  2589. lRet = GetLastError();
  2590. Diagnostics_Write(DVF_ERRORLEVEL, "CreatePropertySheetPage failed, code: %i", lRet);
  2591. hr = DVERR_GENERIC;
  2592. goto error_cleanup;
  2593. }
  2594. // Put it all together...
  2595. ZeroMemory(&psh, sizeof(psh));
  2596. // psh.dwSize = sizeof(psh);
  2597. psh.dwSize = PROPSHEETHEAD_STRUCT_SIZE;
  2598. psh.hInstance = g_hResDLLInstance;
  2599. psh.hwndParent = hwndParent;
  2600. psh.phpage = rghpsp;
  2601. psh.dwFlags = PSH_WIZARD;
  2602. psh.nStartPage = 0;
  2603. psh.nPages = 8;
  2604. sinfo.SetError(DV_OK);
  2605. iRet = (INT) PropertySheet(&psh);
  2606. if (iRet == -1)
  2607. {
  2608. lRet = GetLastError();
  2609. Diagnostics_Write(DVF_ERRORLEVEL, "PropertySheet failed, code: %i", lRet);
  2610. hr = DVERR_GENERIC;
  2611. goto error_cleanup;
  2612. }
  2613. hr = sinfo.DestroyBoldFont();
  2614. if (FAILED(hr))
  2615. {
  2616. Diagnostics_Write(DVF_ERRORLEVEL, "DestroyBoldFont failed");
  2617. goto error_cleanup;
  2618. }
  2619. fBoldFontCreated = FALSE;
  2620. hr = sinfo.DestroyTitleFont();
  2621. if (FAILED(hr))
  2622. {
  2623. Diagnostics_Write(DVF_ERRORLEVEL, "DestroyTitleFont failed");
  2624. goto error_cleanup;
  2625. }
  2626. fTitleFontCreated = FALSE;
  2627. // unregister the peak meter window class
  2628. hr = pmwc.Unregister();
  2629. if (FAILED(hr))
  2630. {
  2631. Diagnostics_Write(DVF_ERRORLEVEL, "CPeakMeterWndClass::Deinit failed, code: %i", hr);
  2632. goto error_cleanup;
  2633. }
  2634. fWndClassRegistered = FALSE;
  2635. if (!FreeLibrary(g_hResDLLInstance))
  2636. {
  2637. lRet = GetLastError();
  2638. Diagnostics_Write(DVF_ERRORLEVEL, "FreeLibrary failed, code: %i", lRet);
  2639. hr = DVERR_WIN32;
  2640. goto error_cleanup;
  2641. }
  2642. g_hResDLLInstance = NULL;
  2643. // see if an error occured
  2644. sinfo.GetError(&hr);
  2645. if (hr == DV_OK)
  2646. {
  2647. // nothing out of the ordinary happened,
  2648. // so we'll return a cancel if the user
  2649. // hit cancel, a "user back" if the user exited
  2650. // the wizard by hitting back from the welcome
  2651. // page, or the results from the registry otherwise.
  2652. sinfo.GetUserCancel(&fUserCancel);
  2653. sinfo.GetUserBack(&fUserBack);
  2654. if (fUserCancel & fUserBack)
  2655. {
  2656. hr = DVERR_USERBACK;
  2657. }
  2658. else if(fUserCancel)
  2659. {
  2660. hr = DVERR_USERCANCEL;
  2661. }
  2662. else
  2663. {
  2664. // look in the registry for the test results
  2665. hr = sinfo.QueryFullDuplex();
  2666. // map a run setup result to a total failure
  2667. if (hr == DVERR_RUNSETUP)
  2668. {
  2669. hr = DVERR_SOUNDINITFAILURE;
  2670. }
  2671. }
  2672. }
  2673. // close the mutex
  2674. sinfo.CloseMutex();
  2675. // close the registry key
  2676. sinfo.CloseRegKey();
  2677. DPF_EXIT();
  2678. return hr;
  2679. error_cleanup:
  2680. if (fBoldFontCreated == TRUE)
  2681. {
  2682. sinfo.DestroyBoldFont();
  2683. }
  2684. fBoldFontCreated = FALSE;
  2685. if (fTitleFontCreated == TRUE)
  2686. {
  2687. sinfo.DestroyTitleFont();
  2688. }
  2689. fTitleFontCreated = FALSE;
  2690. if (fWndClassRegistered == TRUE)
  2691. {
  2692. pmwc.Unregister();
  2693. }
  2694. fWndClassRegistered = FALSE;
  2695. if (g_hResDLLInstance != NULL)
  2696. {
  2697. FreeLibrary(g_hResDLLInstance);
  2698. }
  2699. g_hResDLLInstance = NULL;
  2700. if (fMutexOpen == TRUE)
  2701. {
  2702. sinfo.CloseMutex();
  2703. }
  2704. fMutexOpen = FALSE;
  2705. if (fRegKeyOpen == TRUE)
  2706. {
  2707. sinfo.CloseRegKey();
  2708. }
  2709. fRegKeyOpen = FALSE;
  2710. DPF_EXIT();
  2711. return hr;
  2712. }
  2713. #undef DPF_MODNAME
  2714. #define DPF_MODNAME "SupervisorQueryAudioSetup"
  2715. HRESULT SupervisorQueryAudioSetup(CSupervisorInfo* psinfo)
  2716. {
  2717. DPF_ENTER();
  2718. HRESULT hr;
  2719. // will return DV_HALFDUPLEX, DV_FULLDUPLEX, DVERR_SOUNDINITFAILURE or a real error
  2720. hr = psinfo->QueryFullDuplex();
  2721. if (FAILED(hr) && hr != DVERR_SOUNDINITFAILURE && hr != DVERR_RUNSETUP)
  2722. {
  2723. Diagnostics_Write(DVF_ERRORLEVEL, "QueryFullDuplex failed, code: %i", hr);
  2724. }
  2725. DPF_EXIT();
  2726. return hr;
  2727. }
  2728. #undef DPF_MODNAME
  2729. #define DPF_MODNAME "CSupervisorInfo::CreateTitleFont"
  2730. HRESULT CSupervisorInfo::CreateTitleFont()
  2731. {
  2732. DPF_ENTER();
  2733. LONG lRet;
  2734. HRESULT hr;
  2735. HFONT hfTitle = NULL;
  2736. INT iFontSize;
  2737. LOGFONT lfTitle;
  2738. HDC hdc = NULL;
  2739. NONCLIENTMETRICS ncm;
  2740. DNEnterCriticalSection(&m_csLock);
  2741. // Set up the font for the titles on the intro and ending pages
  2742. ZeroMemory(&ncm, sizeof(ncm));
  2743. ncm.cbSize = sizeof(ncm);
  2744. if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
  2745. {
  2746. lRet = GetLastError();
  2747. Diagnostics_Write(DVF_ERRORLEVEL, "SystemParametersInfo failed, code: %i", lRet);
  2748. hr = DVERR_GENERIC;
  2749. goto error_cleanup;
  2750. }
  2751. // Create the intro/end title font
  2752. lfTitle = ncm.lfMessageFont;
  2753. lfTitle.lfWeight = FW_BOLD;
  2754. lstrcpy(lfTitle.lfFaceName, TEXT("MS Shell Dlg"));
  2755. hdc = GetDC(NULL); //gets the screen DC
  2756. if (hdc == NULL)
  2757. {
  2758. lRet = GetLastError();
  2759. Diagnostics_Write(DVF_ERRORLEVEL, "GetDC failed, code: %i", lRet);
  2760. hr = DVERR_GENERIC;
  2761. goto error_cleanup;
  2762. }
  2763. iFontSize = 12;
  2764. lfTitle.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * iFontSize / 72;
  2765. hfTitle = CreateFontIndirect(&lfTitle);
  2766. if (hfTitle == NULL)
  2767. {
  2768. lRet = GetLastError();
  2769. Diagnostics_Write(DVF_ERRORLEVEL, "CreateFontIndirect failed, code: %i", lRet);
  2770. hr = DVERR_GENERIC;
  2771. goto error_cleanup;
  2772. }
  2773. if (ReleaseDC(NULL, hdc) != 1)
  2774. {
  2775. hdc = NULL;
  2776. lRet = GetLastError();
  2777. Diagnostics_Write(DVF_ERRORLEVEL, "ReleaseDC failed, code: %i", lRet);
  2778. hr = DVERR_GENERIC;
  2779. goto error_cleanup;
  2780. }
  2781. // save the font
  2782. m_hfTitle = hfTitle;
  2783. DNLeaveCriticalSection(&m_csLock);
  2784. DPF_EXIT();
  2785. return DV_OK;
  2786. error_cleanup:
  2787. if (hfTitle != NULL)
  2788. {
  2789. DeleteObject(hfTitle);
  2790. }
  2791. hfTitle = NULL;
  2792. if (hdc != NULL)
  2793. {
  2794. ReleaseDC(NULL, hdc);
  2795. }
  2796. hdc = NULL;
  2797. DNLeaveCriticalSection(&m_csLock);
  2798. DPF_EXIT();
  2799. return hr;
  2800. }
  2801. #undef DPF_MODNAME
  2802. #define DPF_MODNAME "CSupervisorInfo::DestroyTitleFont"
  2803. HRESULT CSupervisorInfo::DestroyTitleFont()
  2804. {
  2805. DPF_ENTER();
  2806. HFONT hTitleFont;
  2807. LONG lRet;
  2808. HRESULT hr;
  2809. DNEnterCriticalSection(&m_csLock);
  2810. if (m_hfTitle == NULL)
  2811. {
  2812. Diagnostics_Write(DVF_ERRORLEVEL, "m_hTitleFont is Null");
  2813. hr = DVERR_GENERIC;
  2814. goto error_cleanup;
  2815. }
  2816. if (!DeleteObject(m_hfTitle))
  2817. {
  2818. lRet = GetLastError();
  2819. Diagnostics_Write(DVF_ERRORLEVEL, "DeleteObject failed, code: %i", lRet);
  2820. hr = DVERR_GENERIC;
  2821. goto error_cleanup;
  2822. }
  2823. DNLeaveCriticalSection(&m_csLock);
  2824. DPF_EXIT();
  2825. return DV_OK;
  2826. error_cleanup:
  2827. DNLeaveCriticalSection(&m_csLock);
  2828. DPF_EXIT();
  2829. return hr;
  2830. }
  2831. #undef DPF_MODNAME
  2832. #define DPF_MODNAME "CSupervisorInfo::CreateBoldFont"
  2833. HRESULT CSupervisorInfo::CreateBoldFont()
  2834. {
  2835. DPF_ENTER();
  2836. LONG lRet;
  2837. HRESULT hr;
  2838. HFONT hfBold = NULL;
  2839. INT iFontSize;
  2840. LOGFONT lfBold;
  2841. HDC hdc = NULL;
  2842. NONCLIENTMETRICS ncm;
  2843. DNEnterCriticalSection(&m_csLock);
  2844. // Set up the font for the titles on the intro and ending pages
  2845. ZeroMemory(&ncm, sizeof(ncm));
  2846. ncm.cbSize = sizeof(ncm);
  2847. if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
  2848. {
  2849. lRet = GetLastError();
  2850. Diagnostics_Write(DVF_ERRORLEVEL, "SystemParametersInfo failed, code: %i", lRet);
  2851. hr = DVERR_GENERIC;
  2852. goto error_cleanup;
  2853. }
  2854. // Create the intro/end title font
  2855. lfBold = ncm.lfMessageFont;
  2856. lfBold.lfWeight = FW_BOLD;
  2857. lstrcpy(lfBold.lfFaceName, TEXT("MS Shell Dlg"));
  2858. hdc = GetDC(NULL); //gets the screen DC
  2859. if (hdc == NULL)
  2860. {
  2861. lRet = GetLastError();
  2862. Diagnostics_Write(DVF_ERRORLEVEL, "GetDC failed, code: %i", lRet);
  2863. hr = DVERR_GENERIC;
  2864. goto error_cleanup;
  2865. }
  2866. iFontSize = 8;
  2867. lfBold.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * iFontSize / 72;
  2868. hfBold = CreateFontIndirect(&lfBold);
  2869. if (hfBold == NULL)
  2870. {
  2871. lRet = GetLastError();
  2872. Diagnostics_Write(DVF_ERRORLEVEL, "CreateFontIndirect failed, code: %i", lRet);
  2873. hr = DVERR_GENERIC;
  2874. goto error_cleanup;
  2875. }
  2876. if (ReleaseDC(NULL, hdc) != 1)
  2877. {
  2878. hdc = NULL;
  2879. lRet = GetLastError();
  2880. Diagnostics_Write(DVF_ERRORLEVEL, "ReleaseDC failed, code: %i", lRet);
  2881. hr = DVERR_GENERIC;
  2882. goto error_cleanup;
  2883. }
  2884. // save the font
  2885. m_hfBold = hfBold;
  2886. DNLeaveCriticalSection(&m_csLock);
  2887. DPF_EXIT();
  2888. return DV_OK;
  2889. error_cleanup:
  2890. if (hdc != NULL)
  2891. {
  2892. ReleaseDC(NULL, hdc);
  2893. }
  2894. hdc = NULL;
  2895. if (hfBold != NULL)
  2896. {
  2897. DeleteObject(hfBold);
  2898. }
  2899. hfBold = NULL;
  2900. DNLeaveCriticalSection(&m_csLock);
  2901. DPF_EXIT();
  2902. return hr;
  2903. }
  2904. #undef DPF_MODNAME
  2905. #define DPF_MODNAME "CSupervisorInfo::DestroyBoldFont"
  2906. HRESULT CSupervisorInfo::DestroyBoldFont()
  2907. {
  2908. DPF_ENTER();
  2909. HFONT hTitleFont;
  2910. LONG lRet;
  2911. HRESULT hr;
  2912. DNEnterCriticalSection(&m_csLock);
  2913. if (m_hfBold == NULL)
  2914. {
  2915. Diagnostics_Write(DVF_ERRORLEVEL, "m_hTitleFont is Null");
  2916. hr = DVERR_GENERIC;
  2917. goto error_cleanup;
  2918. }
  2919. if (!DeleteObject(m_hfBold))
  2920. {
  2921. lRet = GetLastError();
  2922. Diagnostics_Write(DVF_ERRORLEVEL, "DeleteObject failed, code: %i", lRet);
  2923. hr = DVERR_GENERIC;
  2924. goto error_cleanup;
  2925. }
  2926. m_hfBold = NULL;
  2927. DNLeaveCriticalSection(&m_csLock);
  2928. DPF_EXIT();
  2929. return DV_OK;
  2930. error_cleanup:
  2931. DNLeaveCriticalSection(&m_csLock);
  2932. DPF_EXIT();
  2933. return hr;
  2934. }
  2935. #undef DPF_MODNAME
  2936. #define DPF_MODNAME "CSupervisorInfo::Unmute"
  2937. HRESULT CSupervisorInfo::Unmute()
  2938. {
  2939. DPF_ENTER();
  2940. LONG lRet;
  2941. HRESULT hr;
  2942. DVCLIENTCONFIG dvcc;
  2943. DNEnterCriticalSection(&m_csLock);
  2944. if (m_lpdpvc == NULL)
  2945. {
  2946. Diagnostics_Write(DVF_ERRORLEVEL, "NULL IDirectPlayVoiceClient");
  2947. hr = DVERR_INVALIDPARAM;
  2948. goto error_cleanup;
  2949. }
  2950. dvcc.dwSize = sizeof(dvcc);
  2951. hr = m_lpdpvc->GetClientConfig(&dvcc);
  2952. if (FAILED(hr))
  2953. {
  2954. Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetClientConfig failed, hr: %i", hr);
  2955. goto error_cleanup;
  2956. }
  2957. dvcc.dwFlags &= (~DVCLIENTCONFIG_PLAYBACKMUTE);
  2958. m_lpdpvc->SetClientConfig(&dvcc);
  2959. if (FAILED(hr))
  2960. {
  2961. Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::SetClientConfig failed, hr: %i", hr);
  2962. goto error_cleanup;
  2963. }
  2964. DNLeaveCriticalSection(&m_csLock);
  2965. DPF_EXIT();
  2966. return DV_OK;
  2967. error_cleanup:
  2968. DNLeaveCriticalSection(&m_csLock);
  2969. DPF_EXIT();
  2970. return hr;
  2971. }
  2972. #undef DPF_MODNAME
  2973. #define DPF_MODNAME "CSupervisorInfo::Mute"
  2974. HRESULT CSupervisorInfo::Mute()
  2975. {
  2976. DPF_ENTER();
  2977. LONG lRet;
  2978. HRESULT hr;
  2979. DVCLIENTCONFIG dvcc;
  2980. DNEnterCriticalSection(&m_csLock);
  2981. if (m_lpdpvc == NULL)
  2982. {
  2983. Diagnostics_Write(DVF_ERRORLEVEL, "NULL IDirectPlayVoiceClient");
  2984. hr = DVERR_INVALIDPARAM;
  2985. goto error_cleanup;
  2986. }
  2987. dvcc.dwSize = sizeof(dvcc);
  2988. hr = m_lpdpvc->GetClientConfig(&dvcc);
  2989. if (FAILED(hr))
  2990. {
  2991. Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetClientConfig failed, hr: %i", hr);
  2992. goto error_cleanup;
  2993. }
  2994. dvcc.dwFlags |= DVCLIENTCONFIG_PLAYBACKMUTE;
  2995. m_lpdpvc->SetClientConfig(&dvcc);
  2996. if (FAILED(hr))
  2997. {
  2998. Diagnostics_Write(DVF_ERRORLEVEL, "IDirectPlayVoiceClient::SetClientConfig failed, hr: %i", hr);
  2999. goto error_cleanup;
  3000. }
  3001. DNLeaveCriticalSection(&m_csLock);
  3002. DPF_EXIT();
  3003. return DV_OK;
  3004. error_cleanup:
  3005. DNLeaveCriticalSection(&m_csLock);
  3006. DPF_EXIT();
  3007. return hr;
  3008. }
  3009. #undef DPF_MODNAME
  3010. #define DPF_MODNAME "CSupervisorInfo::DSEnumCallback"
  3011. BOOL CALLBACK CSupervisorInfo::DSEnumCallback(
  3012. LPGUID lpGuid,
  3013. LPCTSTR lpcstrDescription,
  3014. LPCTSTR lpcstrModule,
  3015. LPVOID lpContext)
  3016. {
  3017. DNASSERT(lpContext);
  3018. CSupervisorInfo* psinfo = (CSupervisorInfo*)lpContext;
  3019. if (lpGuid)
  3020. {
  3021. if (psinfo->m_guidRenderDevice == *lpGuid)
  3022. {
  3023. // matching guid, copy the description
  3024. _tcsncpy(psinfo->m_szRenderDeviceDesc, lpcstrDescription, MAX_DEVICE_DESC_LEN-1);
  3025. // all done, stop enum
  3026. return FALSE;
  3027. }
  3028. }
  3029. return TRUE;
  3030. }
  3031. #undef DPF_MODNAME
  3032. #define DPF_MODNAME "CSupervisorInfo::DSCEnumCallback"
  3033. BOOL CALLBACK CSupervisorInfo::DSCEnumCallback(
  3034. LPGUID lpGuid,
  3035. LPCTSTR lpcstrDescription,
  3036. LPCTSTR lpcstrModule,
  3037. LPVOID lpContext)
  3038. {
  3039. DNASSERT(lpContext);
  3040. CSupervisorInfo* psinfo = (CSupervisorInfo*)lpContext;
  3041. if (lpGuid)
  3042. {
  3043. if (psinfo->m_guidCaptureDevice == *lpGuid)
  3044. {
  3045. // matching guid, copy the description
  3046. _tcsncpy(psinfo->m_szCaptureDeviceDesc, lpcstrDescription, MAX_DEVICE_DESC_LEN-1);
  3047. // all done, stop enum
  3048. return FALSE;
  3049. }
  3050. }
  3051. return TRUE;
  3052. }
  3053. #undef DPF_MODNAME
  3054. #define DPF_MODNAME "CSupervisorInfo::GetDeviceDescriptions"
  3055. HRESULT CSupervisorInfo::GetDeviceDescriptions()
  3056. {
  3057. DPF_ENTER();
  3058. HRESULT hr;
  3059. TDirectSoundEnumFnc fpDSEnum;
  3060. TDirectSoundEnumFnc fpDSCEnum;
  3061. DNEnterCriticalSection(&m_csLock);
  3062. ZeroMemory(m_szRenderDeviceDesc, MAX_DEVICE_DESC_LEN);
  3063. ZeroMemory(m_szCaptureDeviceDesc, MAX_DEVICE_DESC_LEN);
  3064. HINSTANCE hDSound = LoadLibrary(_T("dsound.dll"));
  3065. if (hDSound == NULL)
  3066. {
  3067. Diagnostics_Write(DVF_ERRORLEVEL, "Error loading dsound.dll");
  3068. hr = DVERR_SOUNDINITFAILURE;
  3069. goto error_cleanup;
  3070. }
  3071. #ifdef UNICODE
  3072. fpDSEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundEnumerateW");
  3073. #else
  3074. fpDSEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundEnumerateA");
  3075. #endif
  3076. if (fpDSEnum == NULL)
  3077. {
  3078. Diagnostics_Write(DVF_ERRORLEVEL, "GetProcAddress failed for DirectSoundEnumerateW");
  3079. hr = DVERR_SOUNDINITFAILURE;
  3080. goto error_cleanup;
  3081. }
  3082. #ifdef UNICODE
  3083. fpDSCEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundCaptureEnumerateW");
  3084. #else
  3085. fpDSCEnum = (TDirectSoundEnumFnc)GetProcAddress(hDSound, "DirectSoundCaptureEnumerateA");
  3086. #endif
  3087. if (fpDSCEnum == NULL)
  3088. {
  3089. Diagnostics_Write(DVF_ERRORLEVEL, "GetProcAddress failed for DirectSoundCaptureEnumerateW");
  3090. hr = DVERR_SOUNDINITFAILURE;
  3091. goto error_cleanup;
  3092. }
  3093. hr = fpDSEnum(DSEnumCallback, (LPVOID)this);
  3094. if (FAILED(hr))
  3095. {
  3096. Diagnostics_Write(DVF_ERRORLEVEL, "DirectSoundEnumerate failed, code: %i, assuming bad guid", hr);
  3097. hr = DVERR_INVALIDDEVICE;
  3098. goto error_cleanup;
  3099. }
  3100. if (m_szRenderDeviceDesc[0] == NULL)
  3101. {
  3102. // the device wasn't found!
  3103. Diagnostics_Write(DVF_ERRORLEVEL, "Render device not found");
  3104. hr = DVERR_INVALIDDEVICE;
  3105. goto error_cleanup;
  3106. }
  3107. hr = fpDSCEnum(DSCEnumCallback, (LPVOID)this);
  3108. if (FAILED(hr))
  3109. {
  3110. Diagnostics_Write(DVF_ERRORLEVEL, "DirectSoundCaptureEnumerate failed, code: %i, assuming bad guid", hr);
  3111. hr = DVERR_INVALIDDEVICE;
  3112. goto error_cleanup;
  3113. }
  3114. if (m_szCaptureDeviceDesc[0] == NULL)
  3115. {
  3116. // the device wasn't found!
  3117. Diagnostics_Write(DVF_ERRORLEVEL, "Capture device not found");
  3118. hr = DVERR_INVALIDDEVICE;
  3119. goto error_cleanup;
  3120. }
  3121. FreeLibrary( hDSound );
  3122. DNLeaveCriticalSection(&m_csLock);
  3123. DPF_EXIT();
  3124. return DV_OK;
  3125. error_cleanup:
  3126. if( hDSound != NULL )
  3127. {
  3128. FreeLibrary( hDSound );
  3129. }
  3130. DNLeaveCriticalSection(&m_csLock);
  3131. DPF_EXIT();
  3132. return hr;
  3133. }
  3134. #undef DPF_MODNAME
  3135. #define DPF_MODNAME "CSupervisorInfo::CloseRegKey"
  3136. HRESULT CSupervisorInfo::CloseRegKey()
  3137. {
  3138. DPF_ENTER();
  3139. LONG lRet;
  3140. HRESULT hr;
  3141. DNEnterCriticalSection(&m_csLock);
  3142. if (!m_creg.Close())
  3143. {
  3144. Diagnostics_Write(DVF_ERRORLEVEL, "CRegistry::Close failed");
  3145. hr = DVERR_GENERIC;
  3146. goto error_cleanup;
  3147. }
  3148. DNLeaveCriticalSection(&m_csLock);
  3149. DPF_EXIT();
  3150. return S_OK;
  3151. error_cleanup:
  3152. DNLeaveCriticalSection(&m_csLock);
  3153. DPF_EXIT();
  3154. return hr;
  3155. }
  3156. #undef DPF_MODNAME
  3157. #define DPF_MODNAME "FullDuplexTestThreadProc"
  3158. DWORD WINAPI FullDuplexTestThreadProc(LPVOID lpvParam)
  3159. {
  3160. DPF_ENTER();
  3161. CSupervisorInfo* lpsinfo;
  3162. HKEY hkDevice;
  3163. HRESULT hr;
  3164. LONG lRet;
  3165. HWND hwnd;
  3166. lpsinfo = (CSupervisorInfo*)lpvParam;
  3167. lpsinfo->GetHWNDDialog(&hwnd);
  3168. hr = RunFullDuplexTest(lpsinfo);
  3169. // post a message to the wizard so it knows we're done, but
  3170. // only if this was not a user cancel, since the wizard will
  3171. // already be waiting on the thread object
  3172. if (hr != DVERR_USERCANCEL)
  3173. {
  3174. if (!PostMessage(hwnd, WM_APP_FULLDUP_TEST_COMPLETE, 0, (LPARAM)hr))
  3175. {
  3176. lRet = GetLastError();
  3177. Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet);
  3178. hr = DVERR_GENERIC;
  3179. }
  3180. }
  3181. DPF_EXIT();
  3182. return hr;
  3183. }
  3184. #undef DPF_MODNAME
  3185. #define DPF_MODNAME "RunFullDuplexTest"
  3186. static HRESULT RunFullDuplexTest(CSupervisorInfo* lpsinfo)
  3187. {
  3188. DPF_ENTER();
  3189. HRESULT hr;
  3190. HRESULT hrFnc;
  3191. CSupervisorIPC* lpsipc;
  3192. lpsinfo->GetIPC(&lpsipc);
  3193. hr = lpsipc->StartPriorityProcess();
  3194. if (FAILED(hr))
  3195. {
  3196. Diagnostics_Write(DVF_ERRORLEVEL, "StartPriorityProcess failed, hr: %i", hr);
  3197. goto error_cleanup;
  3198. }
  3199. hr = lpsipc->StartFullDuplexProcess();
  3200. if (FAILED(hr))
  3201. {
  3202. Diagnostics_Write(DVF_ERRORLEVEL, "StartFullDuplexProcess failed, hr: %i", hr);
  3203. goto error_cleanup;
  3204. }
  3205. hrFnc = DoTests(lpsinfo);
  3206. hr = lpsipc->WaitOnChildren();
  3207. if (FAILED(hr))
  3208. {
  3209. Diagnostics_Write(DVF_ERRORLEVEL, "WaitOnChildren failed, code: %i", hr);
  3210. goto error_cleanup;
  3211. }
  3212. DPF_EXIT();
  3213. return hrFnc;
  3214. error_cleanup:
  3215. // this function is safe to call, even if the child processes have not
  3216. // been created
  3217. lpsipc->TerminateChildProcesses();
  3218. DPF_EXIT();
  3219. return hr;
  3220. }
  3221. #undef DPF_MODNAME
  3222. #define DPF_MODNAME "CSupervisorInfo::CrashCheckIn"
  3223. HRESULT CSupervisorInfo::CrashCheckIn()
  3224. {
  3225. DPF_ENTER();
  3226. LONG lRet;
  3227. BOOL fRet;
  3228. DWORD dwRegVal;
  3229. HRESULT hrFnc;
  3230. HRESULT hr;
  3231. HKEY hk;
  3232. // Each of the following three functions take the critical section,
  3233. // so there is no need to take it here.
  3234. // Check each of the test results to see if any tests
  3235. // crashed.
  3236. hr = GetHalfDuplex(&dwRegVal);
  3237. if (!FAILED(hr) && dwRegVal == REGVAL_CRASHED)
  3238. {
  3239. // The half duplex test crashed.
  3240. Diagnostics_Write(DVF_ERRORLEVEL, "Previous half duplex test crashed");
  3241. hrFnc = DVERR_PREVIOUSCRASH;
  3242. goto error_cleanup;
  3243. }
  3244. hr = GetFullDuplex(&dwRegVal);
  3245. if (!FAILED(hr) && dwRegVal == REGVAL_CRASHED)
  3246. {
  3247. // The full duplex test crashed.
  3248. Diagnostics_Write(DVF_ERRORLEVEL, "Previous full duplex test crashed");
  3249. hrFnc = DVERR_PREVIOUSCRASH;
  3250. goto error_cleanup;
  3251. }
  3252. hr = GetMicDetected(&dwRegVal);
  3253. if (!FAILED(hr) && dwRegVal == REGVAL_CRASHED)
  3254. {
  3255. // The mic test crashed.
  3256. Diagnostics_Write(DVF_ERRORLEVEL, "Previous mic test crashed");
  3257. hrFnc = DVERR_PREVIOUSCRASH;
  3258. goto error_cleanup;
  3259. }
  3260. DPF_EXIT();
  3261. return DV_OK;
  3262. // error block
  3263. error_cleanup:
  3264. DPF_EXIT();
  3265. return hrFnc;
  3266. }
  3267. #undef DPF_MODNAME
  3268. #define DPF_MODNAME "DoTests"
  3269. HRESULT DoTests(CSupervisorInfo* lpsinfo)
  3270. {
  3271. DPF_ENTER();
  3272. LONG lRet;
  3273. DWORD dwRet;
  3274. HANDLE rghEvents[2];
  3275. HRESULT hr;
  3276. HRESULT hrFnc;
  3277. CSupervisorIPC* lpsipc;
  3278. lpsinfo->GetIPC(&lpsipc);
  3279. // wait until the child processes are ready to go...
  3280. hr = lpsipc->WaitForStartupSignals();
  3281. if (FAILED(hr))
  3282. {
  3283. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForStartupSignals failed, hr: %i", hr);
  3284. goto error_cleanup;
  3285. }
  3286. // child processes are all set, tell them what to do
  3287. // Note: this function has only four expected return codes
  3288. // DV_FULLDUPLEX - all tests passed
  3289. // DV_HALFDUPLEX - all half duplex tests passed, full duplex tests failed
  3290. // DVERR_SOUNDINITFAILURE - half duplex tests failed
  3291. // DVERR_USERCANCEL - tests canceled by user
  3292. hrFnc = IssueCommands(lpsinfo);
  3293. if (FAILED(hrFnc)
  3294. && hrFnc != DVERR_SOUNDINITFAILURE
  3295. && hrFnc != DVERR_USERCANCEL)
  3296. {
  3297. Diagnostics_Write(DVF_ERRORLEVEL, "IssueCommands failed, hr: %i", hrFnc);
  3298. hr = hrFnc;
  3299. goto error_cleanup;
  3300. }
  3301. // now tell the child processes to shut down
  3302. hr = IssueShutdownCommand(lpsipc);
  3303. if (FAILED(hr))
  3304. {
  3305. Diagnostics_Write(DVF_ERRORLEVEL, "IssueShutdownCommand failed, code: %i", hr);
  3306. // Note we're not bailing out. We have our test results, so this is
  3307. // a problem somewhere in the wizard code. Return the result
  3308. // from the actual test.
  3309. }
  3310. DPF_EXIT();
  3311. return hrFnc;
  3312. error_cleanup:
  3313. // attempt to gracefully shutdown child processes.
  3314. IssueShutdownCommand(lpsipc);
  3315. DPF_EXIT();
  3316. return hr;
  3317. }
  3318. #undef DPF_MODNAME
  3319. #define DPF_MODNAME "IssueCommands"
  3320. HRESULT IssueCommands(CSupervisorInfo* lpsinfo)
  3321. {
  3322. // Note: this function has only four possible return codes
  3323. // DV_FULLDUPLEX - all tests passed
  3324. // DV_HALFDUPLEX - all half duplex tests passed, full duplex tests failed
  3325. // DVERR_SOUNDINITFAILURE - half duplex tests failed
  3326. // DVERR_USERCANCEL - tests canceled by user
  3327. DPF_ENTER();
  3328. HRESULT hr;
  3329. DWORD dwIndex1;
  3330. DWORD dwIndex2;
  3331. BOOL fAbort = FALSE;
  3332. BOOL fPassed;
  3333. // First do a pass testing that we can run in
  3334. // half duplex without error.
  3335. // Set the half duplex key to crash state
  3336. lpsinfo->SetHalfDuplex(REGVAL_CRASHED);
  3337. dwIndex1 = 0;
  3338. fPassed = FALSE;
  3339. while (1)
  3340. {
  3341. if (gc_rgwfxPrimaryFormats[dwIndex1].wFormatTag == 0
  3342. && gc_rgwfxPrimaryFormats[dwIndex1].nChannels == 0
  3343. && gc_rgwfxPrimaryFormats[dwIndex1].nSamplesPerSec == 0
  3344. && gc_rgwfxPrimaryFormats[dwIndex1].nAvgBytesPerSec == 0
  3345. && gc_rgwfxPrimaryFormats[dwIndex1].nBlockAlign == 0
  3346. && gc_rgwfxPrimaryFormats[dwIndex1].wBitsPerSample == 0
  3347. && gc_rgwfxPrimaryFormats[dwIndex1].cbSize == 0)
  3348. {
  3349. // we've found the last element of the array, break out.
  3350. fPassed = TRUE;
  3351. break;
  3352. }
  3353. lpsinfo->GetAbortFullDuplex(&fAbort);
  3354. if (fAbort)
  3355. {
  3356. // abort the tests
  3357. break;
  3358. }
  3359. hr = lpsinfo->TestCase(&gc_rgwfxPrimaryFormats[dwIndex1], DVSOUNDCONFIG_HALFDUPLEX|DVSOUNDCONFIG_TESTMODE);
  3360. if (hr != DV_HALFDUPLEX)
  3361. {
  3362. Diagnostics_Write(DVF_ERRORLEVEL, "Half duplex test case not supported hr = 0x%x", hr);
  3363. break;
  3364. }
  3365. ++dwIndex1;
  3366. // Why is this here? Because DSOUND doesn't like you to open/close quickly.
  3367. Sleep( 200 );
  3368. }
  3369. if (fAbort)
  3370. {
  3371. // The user aborted the tests, make it like they were never run.
  3372. lpsinfo->SetHalfDuplex(REGVAL_NOTRUN);
  3373. DPF_EXIT();
  3374. return DVERR_USERCANCEL;
  3375. }
  3376. // Record the results of the half duplex test in the registry,
  3377. // and decide what to do next.
  3378. if (fPassed)
  3379. {
  3380. lpsinfo->SetHalfDuplex(REGVAL_PASSED);
  3381. // continue on with the full duplex test.
  3382. }
  3383. else
  3384. {
  3385. lpsinfo->SetHalfDuplex(REGVAL_FAILED);
  3386. // we failed the half duplex test, we're done.
  3387. DPF_EXIT();
  3388. // map all failures at this point to sound problems.
  3389. return DVERR_SOUNDINITFAILURE;
  3390. }
  3391. // Now that we're finished testing in half duplex mode,
  3392. // we can move on to the full duplex testing.
  3393. lpsinfo->SetFullDuplex(REGVAL_CRASHED);
  3394. fPassed = FALSE;
  3395. dwIndex1 = 0;
  3396. while (1)
  3397. {
  3398. if (gc_rgwfxPrimaryFormats[dwIndex1].wFormatTag == 0
  3399. && gc_rgwfxPrimaryFormats[dwIndex1].nChannels == 0
  3400. && gc_rgwfxPrimaryFormats[dwIndex1].nSamplesPerSec == 0
  3401. && gc_rgwfxPrimaryFormats[dwIndex1].nAvgBytesPerSec == 0
  3402. && gc_rgwfxPrimaryFormats[dwIndex1].nBlockAlign == 0
  3403. && gc_rgwfxPrimaryFormats[dwIndex1].wBitsPerSample == 0
  3404. && gc_rgwfxPrimaryFormats[dwIndex1].cbSize == 0)
  3405. {
  3406. // we've found the last element of the array, break out.
  3407. fPassed = TRUE;
  3408. break;
  3409. }
  3410. lpsinfo->GetAbortFullDuplex(&fAbort);
  3411. if (fAbort)
  3412. {
  3413. // abort the tests
  3414. break;
  3415. }
  3416. hr = lpsinfo->TestCase(&gc_rgwfxPrimaryFormats[dwIndex1], DVSOUNDCONFIG_TESTMODE);
  3417. if (hr != DV_FULLDUPLEX)
  3418. {
  3419. Diagnostics_Write(DVF_ERRORLEVEL, "Full duplex test case not supported. hr = 0x%x", hr);
  3420. break;
  3421. }
  3422. ++dwIndex1;
  3423. // Why is this here? Because DSOUND doesn't like you to open/close quickly.
  3424. Sleep( 200 );
  3425. }
  3426. if (fAbort)
  3427. {
  3428. // The user aborted the tests, make it like they were never run.
  3429. lpsinfo->SetFullDuplex(REGVAL_NOTRUN);
  3430. DPF_EXIT();
  3431. return DVERR_USERCANCEL;
  3432. }
  3433. // Record the results of the full duplex test in the registry,
  3434. // and return the appropriate code.
  3435. if (fPassed)
  3436. {
  3437. lpsinfo->SetFullDuplex(REGVAL_PASSED);
  3438. DPF_EXIT();
  3439. return DV_FULLDUPLEX;
  3440. }
  3441. else
  3442. {
  3443. lpsinfo->SetFullDuplex(REGVAL_FAILED);
  3444. DPF_EXIT();
  3445. return DV_HALFDUPLEX;
  3446. }
  3447. }
  3448. #undef DPF_MODNAME
  3449. #define DPF_MODNAME "CSupervisorInfo::TestCase"
  3450. HRESULT CSupervisorInfo::TestCase(const WAVEFORMATEX* lpwfxPrimary, DWORD dwFlags)
  3451. {
  3452. DPF_ENTER();
  3453. HRESULT hr = DV_OK;
  3454. HRESULT hrFnc = DV_OK;
  3455. SFDTestCommand fdtc;
  3456. // tell the priority process to go
  3457. ZeroMemory(&fdtc, sizeof(fdtc));
  3458. fdtc.dwSize = sizeof(fdtc);
  3459. fdtc.fdtcc = fdtccPriorityStart;
  3460. fdtc.fdtu.fdtcPriorityStart.guidRenderDevice = m_guidRenderDevice;
  3461. fdtc.fdtu.fdtcPriorityStart.wfxRenderFormat = *lpwfxPrimary;
  3462. fdtc.fdtu.fdtcPriorityStart.wfxSecondaryFormat = gc_wfxSecondaryFormat;
  3463. fdtc.fdtu.fdtcPriorityStart.hwndWizard = m_hwndWizard;
  3464. fdtc.fdtu.fdtcPriorityStart.hwndProgress = m_hwndProgress;
  3465. hr = m_sipc.SendToPriority(&fdtc);
  3466. if (FAILED(hr))
  3467. {
  3468. DPF_EXIT();
  3469. return hr;
  3470. }
  3471. // tell the full duplex process to attempt full duplex
  3472. ZeroMemory(&fdtc, sizeof(fdtc));
  3473. fdtc.dwSize = sizeof(fdtc);
  3474. fdtc.fdtcc = fdtccFullDuplexStart;
  3475. fdtc.fdtu.fdtcFullDuplexStart.guidRenderDevice = m_guidRenderDevice;
  3476. fdtc.fdtu.fdtcFullDuplexStart.guidCaptureDevice = m_guidCaptureDevice;
  3477. fdtc.fdtu.fdtcFullDuplexStart.dwFlags = dwFlags;
  3478. hrFnc = m_sipc.SendToFullDuplex(&fdtc);
  3479. if (FAILED(hrFnc))
  3480. {
  3481. // The full duplex process was unable to do it.
  3482. // tell the priority process to stop and get out.
  3483. ZeroMemory(&fdtc, sizeof(fdtc));
  3484. fdtc.dwSize = sizeof(fdtc);
  3485. fdtc.fdtcc = fdtccPriorityStop;
  3486. m_sipc.SendToPriority(&fdtc);
  3487. DPF_EXIT();
  3488. return hrFnc;
  3489. }
  3490. // Wait for a half second before we shut it down.
  3491. // This gives it the time required for the sound system
  3492. // to detect a lockup if it is going to.
  3493. Sleep(1000);
  3494. // The full duplex process was ok, till now. Try to
  3495. // shut it down.
  3496. ZeroMemory(&fdtc, sizeof(fdtc));
  3497. fdtc.dwSize = sizeof(fdtc);
  3498. fdtc.fdtcc = fdtccFullDuplexStop;
  3499. hr = m_sipc.SendToFullDuplex(&fdtc);
  3500. if (FAILED(hr))
  3501. {
  3502. // It looks like the full duplex wasn't quite up to stuff
  3503. // after all. Tell the priority process to shut down
  3504. ZeroMemory(&fdtc, sizeof(fdtc));
  3505. fdtc.dwSize = sizeof(fdtc);
  3506. fdtc.fdtcc = fdtccPriorityStop;
  3507. m_sipc.SendToPriority(&fdtc);
  3508. DPF_EXIT();
  3509. return hr;
  3510. }
  3511. // All is well, up to now, one last hurdle...
  3512. ZeroMemory(&fdtc, sizeof(fdtc));
  3513. fdtc.dwSize = sizeof(fdtc);
  3514. fdtc.fdtcc = fdtccPriorityStop;
  3515. hr = m_sipc.SendToPriority(&fdtc);
  3516. if (FAILED(hr))
  3517. {
  3518. DPF_EXIT();
  3519. return hr;
  3520. }
  3521. // you have graduated from full duplex class...
  3522. DPF_EXIT();
  3523. return hrFnc;
  3524. }
  3525. #undef DPF_MODNAME
  3526. #define DPF_MODNAME "IssueShutdownCommand"
  3527. HRESULT IssueShutdownCommand(CSupervisorIPC* lpipcSupervisor)
  3528. {
  3529. SFDTestCommand fdtc;
  3530. HRESULT hr;
  3531. DPF_EXIT();
  3532. fdtc.dwSize = sizeof(fdtc);
  3533. fdtc.fdtcc = fdtccExit;
  3534. hr = lpipcSupervisor->SendToFullDuplex(&fdtc);
  3535. if (FAILED(hr))
  3536. {
  3537. lpipcSupervisor->SendToPriority(&fdtc);
  3538. DPF_EXIT();
  3539. return hr;
  3540. }
  3541. hr = lpipcSupervisor->SendToPriority(&fdtc);
  3542. if (FAILED(hr))
  3543. {
  3544. DPF_EXIT();
  3545. return hr;
  3546. }
  3547. DPF_EXIT();
  3548. return DV_OK;
  3549. }
  3550. #undef DPF_MODNAME
  3551. #define DPF_MODNAME "WelcomeProc"
  3552. INT_PTR CALLBACK WelcomeProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  3553. {
  3554. DPF_ENTER();
  3555. BOOL fRet;
  3556. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  3557. fRet = FALSE;
  3558. switch (message)
  3559. {
  3560. case WM_INITDIALOG :
  3561. fRet = WelcomeInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  3562. break;
  3563. case WM_NOTIFY :
  3564. {
  3565. const NMHDR* lpnm = (LPNMHDR) lParam;
  3566. switch (lpnm->code)
  3567. {
  3568. case PSN_SETACTIVE :
  3569. // Enable the Next button
  3570. fRet = WelcomeSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  3571. break;
  3572. case PSN_WIZBACK :
  3573. // Back button clicked
  3574. fRet = WelcomeBackHandler(hDlg, message, wParam, lParam, psinfo);
  3575. break;
  3576. case PSN_WIZNEXT :
  3577. // Next button clicked
  3578. fRet = WelcomeNextHandler(hDlg, message, wParam, lParam, psinfo);
  3579. break;
  3580. case PSN_RESET :
  3581. fRet = WelcomeResetHandler(hDlg, message, wParam, lParam, psinfo);
  3582. break;
  3583. default :
  3584. break;
  3585. }
  3586. }
  3587. break;
  3588. default:
  3589. break;
  3590. }
  3591. DPF_EXIT();
  3592. return fRet;
  3593. }
  3594. #undef DPF_MODNAME
  3595. #define DPF_MODNAME "WelcomeInitDialogHandler"
  3596. BOOL WelcomeInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3597. {
  3598. DPF_ENTER();
  3599. HWND hwndControl;
  3600. HWND hwndWizard = NULL;
  3601. LONG lRet;
  3602. HFONT hfTitle;
  3603. HICON hIcon;
  3604. HRESULT hr = DV_OK;
  3605. HWND hwndParent = NULL;
  3606. // Get the shared data from PROPSHEETPAGE lParam value
  3607. // and load it into GWLP_USERDATA
  3608. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  3609. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  3610. // Get the parent window
  3611. hwndWizard = GetParent(hDlg);
  3612. if (hwndWizard == NULL)
  3613. {
  3614. lRet = GetLastError();
  3615. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  3616. hr = DVERR_GENERIC;
  3617. goto error_cleanup;
  3618. }
  3619. // It's an intro/end page, so get the title font
  3620. // from the shared data and use it for the title control
  3621. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  3622. if (hwndControl == NULL)
  3623. {
  3624. // error, log it and bail
  3625. lRet = GetLastError();
  3626. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  3627. hr = DVERR_GENERIC;
  3628. goto error_cleanup;
  3629. }
  3630. psinfo->GetTitleFont(&hfTitle);
  3631. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE);
  3632. // load the warning icon
  3633. //hIcon = LoadIcon(NULL, IDI_INFORMATION);
  3634. //SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
  3635. // set the device descriptions
  3636. SendDlgItemMessage(hDlg, IDC_TEXT_PLAYBACK, WM_SETTEXT, 0, (LPARAM)psinfo->GetRenderDesc());
  3637. SendDlgItemMessage(hDlg, IDC_TEXT_RECORDING, WM_SETTEXT, 0, (LPARAM)psinfo->GetCaptureDesc());
  3638. // reset the welcome next flag
  3639. psinfo->ClearWelcomeNext();
  3640. DPF_EXIT();
  3641. return FALSE;
  3642. error_cleanup:
  3643. psinfo->GetHWNDParent(&hwndParent);
  3644. DV_DisplayErrorBox(hr, hwndParent);
  3645. psinfo->SetError(hr);
  3646. psinfo->Abort(hDlg, hr);
  3647. DPF_EXIT();
  3648. return FALSE;
  3649. }
  3650. #undef DPF_MODNAME
  3651. #define DPF_MODNAME "WelcomeSetActiveHandler"
  3652. BOOL WelcomeSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3653. {
  3654. DPF_ENTER();
  3655. HWND hwndParent;
  3656. HWND hwndWizard;
  3657. LONG lRet;
  3658. DWORD dwFlags;
  3659. HRESULT hr;
  3660. // Get the parent window
  3661. hwndWizard = GetParent(hDlg);
  3662. if (hwndWizard == NULL)
  3663. {
  3664. // log it, and return, don't know how to terminate the wizard properly
  3665. // without this handle!
  3666. lRet = GetLastError();
  3667. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  3668. hr = DVERR_GENERIC;
  3669. goto error_cleanup;
  3670. }
  3671. // set the HWNDs
  3672. psinfo->SetHWNDWizard(hwndWizard);
  3673. psinfo->SetHWNDDialog(hDlg);
  3674. psinfo->SetHWNDProgress(NULL);
  3675. psinfo->SetHWNDInputPeak(NULL);
  3676. psinfo->SetHWNDOutputPeak(NULL);
  3677. psinfo->SetHWNDInputVolumeSlider(NULL);
  3678. psinfo->SetHWNDOutputVolumeSlider(NULL);
  3679. // set the appropriate wizard buttons as active.
  3680. psinfo->GetCheckAudioSetupFlags(&dwFlags);
  3681. if (dwFlags & DVFLAGS_ALLOWBACK)
  3682. {
  3683. PropSheet_SetWizButtons(hwndWizard, PSWIZB_NEXT|PSWIZB_BACK);
  3684. }
  3685. else
  3686. {
  3687. PropSheet_SetWizButtons(hwndWizard, PSWIZB_NEXT);
  3688. }
  3689. // reset the user cancel and user back flags
  3690. psinfo->ClearUserCancel();
  3691. psinfo->ClearUserBack();
  3692. DPF_EXIT();
  3693. return FALSE;
  3694. // error block
  3695. error_cleanup:
  3696. psinfo->GetHWNDParent(&hwndParent);
  3697. DV_DisplayErrorBox(hr, hwndParent);
  3698. psinfo->SetError(hr);
  3699. psinfo->Abort(hDlg, hr);
  3700. DPF_EXIT();
  3701. return FALSE;
  3702. }
  3703. #undef DPF_MODNAME
  3704. #define DPF_MODNAME "WelcomeBackHandler"
  3705. BOOL WelcomeBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3706. {
  3707. DPF_ENTER();
  3708. HWND hwndWizard = NULL;
  3709. HRESULT hr = DV_OK;
  3710. HKEY hkey;
  3711. LONG lRet;
  3712. DWORD dwErr;
  3713. DWORD dwRegVal;
  3714. // Get the parent window
  3715. psinfo->GetHWNDWizard(&hwndWizard);
  3716. // The back button was hit on the welcome page. Exit the wizard with the appropriate error code.
  3717. psinfo->SetUserBack();
  3718. PropSheet_PressButton(hwndWizard, PSBTN_CANCEL);
  3719. // no previous crashes (or the user is boldly charging ahead anyway),
  3720. // so go to the full duplex test page
  3721. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST);
  3722. DPF_EXIT();
  3723. return TRUE;
  3724. }
  3725. #undef DPF_MODNAME
  3726. #define DPF_MODNAME "WelcomeNextHandler"
  3727. BOOL WelcomeNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3728. {
  3729. DPF_ENTER();
  3730. HWND hwndWizard = NULL;
  3731. HRESULT hr = DV_OK;
  3732. HKEY hkey;
  3733. LONG lRet;
  3734. DWORD dwErr;
  3735. DWORD dwRegVal;
  3736. HWND hwndParent = NULL;
  3737. // Get the parent window
  3738. psinfo->GetHWNDWizard(&hwndWizard);
  3739. // The next button was hit on the welcome page. Do all the basic init tasks.
  3740. // check for previous crashes
  3741. hr = psinfo->CrashCheckIn();
  3742. if (FAILED(hr))
  3743. {
  3744. if (hr == DVERR_PREVIOUSCRASH)
  3745. {
  3746. // the previous test crashed out, display the warning.
  3747. Diagnostics_Write(DVF_ERRORLEVEL, "DirectPlay Voice Setup Wizard detected previous full duplex test crashed");
  3748. int iRet = (INT) DialogBox(g_hResDLLInstance, MAKEINTRESOURCE(IDD_PREVIOUS_CRASH), hDlg, PreviousCrashProc);
  3749. switch (iRet)
  3750. {
  3751. case IDOK:
  3752. // the previous test crashed, but the user wants to continue
  3753. // anyway, so move along...
  3754. Diagnostics_Write(DVF_ERRORLEVEL, "User choosing to ignore previous failure");
  3755. break;
  3756. case IDCANCEL:
  3757. // the previous test crashed, and the user is wisely choosing
  3758. // to bail out. Go to either the full duplex failed page, or the
  3759. // half duplex failed page, depending on the registry state.
  3760. Diagnostics_Write(DVF_ERRORLEVEL, "User choosing not to run test");
  3761. hr = psinfo->GetHalfDuplex(&dwRegVal);
  3762. if (!FAILED(hr) && dwRegVal == REGVAL_PASSED)
  3763. {
  3764. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXFAILED);
  3765. }
  3766. else
  3767. {
  3768. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_HALFDUPLEXFAILED);
  3769. }
  3770. return TRUE;
  3771. break;
  3772. default:
  3773. // this is an error
  3774. Diagnostics_Write(DVF_ERRORLEVEL, "DialogBox failed");
  3775. hr = DVERR_GENERIC;
  3776. goto error_cleanup;
  3777. }
  3778. }
  3779. else
  3780. {
  3781. Diagnostics_Write(DVF_ERRORLEVEL, "CrashCheckIn failed, code: %i", hr);
  3782. goto error_cleanup;
  3783. }
  3784. }
  3785. // no previous crashes (or the user is boldly charging ahead anyway),
  3786. // so go to the full duplex test page
  3787. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST);
  3788. DPF_EXIT();
  3789. return TRUE;
  3790. error_cleanup:
  3791. psinfo->GetHWNDParent(&hwndParent);
  3792. DV_DisplayErrorBox(hr, hwndParent);
  3793. psinfo->SetError(hr);
  3794. psinfo->Abort(hDlg, hr);
  3795. DPF_EXIT();
  3796. return FALSE;
  3797. }
  3798. #undef DPF_MODNAME
  3799. #define DPF_MODNAME "WelcomeResetHandler"
  3800. BOOL WelcomeResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3801. {
  3802. DPF_ENTER();
  3803. HRESULT hr;
  3804. HWND hwndWizard;
  3805. // disable all buttons
  3806. psinfo->GetHWNDWizard(&hwndWizard);
  3807. PropSheet_SetWizButtons(hwndWizard, 0);
  3808. psinfo->Cancel();
  3809. DPF_EXIT();
  3810. return FALSE;
  3811. }
  3812. /*
  3813. #undef DPF_MODNAME
  3814. #define DPF_MODNAME "AlreadyRunningProc"
  3815. INT_PTR CALLBACK AlreadyRunningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  3816. {
  3817. DPF_ENTER();
  3818. HICON hIcon;
  3819. switch (message)
  3820. {
  3821. case WM_INITDIALOG :
  3822. hIcon = LoadIcon(NULL, IDI_ERROR);
  3823. SendDlgItemMessage(hDlg, IDC_ICON_ERROR, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
  3824. break;
  3825. case WM_COMMAND:
  3826. switch (LOWORD(wParam))
  3827. {
  3828. case IDOK:
  3829. case IDCANCEL:
  3830. EndDialog(hDlg, LOWORD(wParam));
  3831. return TRUE;
  3832. default:
  3833. break;
  3834. }
  3835. break;
  3836. default:
  3837. break;
  3838. }
  3839. DPF_EXIT();
  3840. return FALSE;
  3841. }
  3842. */
  3843. #undef DPF_MODNAME
  3844. #define DPF_MODNAME "PreviousCrashProc"
  3845. INT_PTR CALLBACK PreviousCrashProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  3846. {
  3847. DPF_ENTER();
  3848. HICON hIcon;
  3849. Diagnostics_Write(DVF_ERRORLEVEL, "Previous run crashed");
  3850. switch (message)
  3851. {
  3852. case WM_INITDIALOG :
  3853. PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC );
  3854. hIcon = LoadIcon(NULL, IDI_WARNING);
  3855. SendDlgItemMessage(hDlg, IDC_ICON_WARNING, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
  3856. break;
  3857. case WM_COMMAND:
  3858. switch (LOWORD(wParam))
  3859. {
  3860. case IDOK:
  3861. case IDCANCEL:
  3862. EndDialog(hDlg, LOWORD(wParam));
  3863. return(TRUE);
  3864. break;
  3865. default:
  3866. break;
  3867. }
  3868. break;
  3869. default:
  3870. break;
  3871. }
  3872. DPF_EXIT();
  3873. return FALSE;
  3874. }
  3875. #undef DPF_MODNAME
  3876. #define DPF_MODNAME "FullDuplexProc"
  3877. INT_PTR CALLBACK FullDuplexProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  3878. {
  3879. DPF_ENTER();
  3880. LONG lRet;
  3881. BOOL fRet;
  3882. LPNMHDR lpnm;
  3883. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  3884. fRet = FALSE;
  3885. switch (message)
  3886. {
  3887. case WM_INITDIALOG :
  3888. FullDuplexInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  3889. break;
  3890. case WM_NOTIFY :
  3891. lpnm = (LPNMHDR) lParam;
  3892. switch (lpnm->code)
  3893. {
  3894. case PSN_SETACTIVE :
  3895. fRet = FullDuplexSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  3896. break;
  3897. case PSN_WIZBACK :
  3898. fRet = FullDuplexBackHandler(hDlg, message, wParam, lParam, psinfo);
  3899. break;
  3900. case PSN_WIZNEXT :
  3901. fRet = FullDuplexNextHandler(hDlg, message, wParam, lParam, psinfo);
  3902. break;
  3903. case PSN_RESET :
  3904. fRet = FullDuplexResetHandler(hDlg, message, wParam, lParam, psinfo);
  3905. break;
  3906. default :
  3907. break;
  3908. }
  3909. break;
  3910. case WM_APP_FULLDUP_TEST_COMPLETE:
  3911. fRet = FullDuplexCompleteHandler(hDlg, message, wParam, lParam, psinfo);
  3912. break;
  3913. default:
  3914. break;
  3915. }
  3916. DPF_EXIT();
  3917. return fRet;
  3918. }
  3919. #undef DPF_MODNAME
  3920. #define DPF_MODNAME "FullDuplexInitDialogHandler"
  3921. BOOL FullDuplexInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3922. {
  3923. DPF_ENTER();
  3924. LONG lRet;
  3925. HWND hwndWizard = NULL;
  3926. HWND hwndParent = NULL;
  3927. HWND hwndControl;
  3928. HFONT hfBold;
  3929. HRESULT hr = DV_OK;
  3930. // Get the shared data from PROPSHEETPAGE lParam value
  3931. // and load it into GWLP_USERDATA
  3932. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  3933. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  3934. // Get the parent window
  3935. hwndWizard = GetParent(hDlg);
  3936. if (hwndWizard == NULL)
  3937. {
  3938. lRet = GetLastError();
  3939. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  3940. hr = DVERR_GENERIC;
  3941. goto error_cleanup;
  3942. }
  3943. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  3944. if (hwndControl == NULL)
  3945. {
  3946. // error, log it and bail
  3947. lRet = GetLastError();
  3948. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  3949. hr = DVERR_GENERIC;
  3950. goto error_cleanup;
  3951. }
  3952. psinfo->GetBoldFont(&hfBold);
  3953. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfBold, (LPARAM)TRUE);
  3954. DPF_EXIT();
  3955. return FALSE;
  3956. error_cleanup:
  3957. psinfo->GetHWNDParent(&hwndParent);
  3958. DV_DisplayErrorBox(hr, hwndParent);
  3959. psinfo->SetError(hr);
  3960. psinfo->Abort(hDlg, hr);
  3961. DPF_EXIT();
  3962. return FALSE;
  3963. }
  3964. #undef DPF_MODNAME
  3965. #define DPF_MODNAME "FullDuplexSetActiveHandler"
  3966. BOOL FullDuplexSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  3967. {
  3968. DPF_ENTER();
  3969. LONG lRet;
  3970. HWND hwndWizard = NULL;
  3971. HWND hwndParent = NULL;
  3972. HWND hwndProgress;
  3973. HWND hwndCancelButton;
  3974. HANDLE hThread;
  3975. DWORD dwThreadId;
  3976. WORD wCount;
  3977. HRESULT hr = DV_OK;
  3978. // Get the parent window
  3979. hwndWizard = GetParent(hDlg);
  3980. if (hwndWizard == NULL)
  3981. {
  3982. lRet = GetLastError();
  3983. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  3984. hr = DVERR_GENERIC;
  3985. goto error_cleanup;
  3986. }
  3987. // reset all the test registry bits
  3988. psinfo->SetHalfDuplex(REGVAL_NOTRUN);
  3989. psinfo->SetFullDuplex(REGVAL_NOTRUN);
  3990. psinfo->SetMicDetected(REGVAL_NOTRUN);
  3991. // remember that we've been here, so we'll know to reset the registry
  3992. // if the user hits cancel from this point forward
  3993. psinfo->SetWelcomeNext();
  3994. // get the progress bar's HWND
  3995. hwndProgress = GetDlgItem(hDlg, IDC_PROGRESSBAR);
  3996. if (hwndProgress == NULL)
  3997. {
  3998. lRet = GetLastError();
  3999. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4000. hr = DVERR_GENERIC;
  4001. goto error_cleanup;
  4002. }
  4003. // Init the progress bar...
  4004. // count the number of elements in the primary format array
  4005. wCount = 0;
  4006. while (1)
  4007. {
  4008. // Increment before we test. This means that if there
  4009. // are four formats, wCount will equal five after this
  4010. // loop.
  4011. ++wCount;
  4012. if (gc_rgwfxPrimaryFormats[wCount].wFormatTag == 0
  4013. && gc_rgwfxPrimaryFormats[wCount].nChannels == 0
  4014. && gc_rgwfxPrimaryFormats[wCount].nSamplesPerSec == 0
  4015. && gc_rgwfxPrimaryFormats[wCount].nAvgBytesPerSec == 0
  4016. && gc_rgwfxPrimaryFormats[wCount].nBlockAlign == 0
  4017. && gc_rgwfxPrimaryFormats[wCount].wBitsPerSample == 0
  4018. && gc_rgwfxPrimaryFormats[wCount].cbSize == 0)
  4019. {
  4020. // we've found the last element of the array, break out.
  4021. break;
  4022. }
  4023. }
  4024. // set up the progress bar with one segment for each
  4025. // primary format, times two, since each is tested in
  4026. // both half and full duplex.
  4027. SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, wCount*2));
  4028. SendMessage(hwndProgress, PBM_SETPOS, 0, 0);
  4029. SendMessage(hwndProgress, PBM_SETSTEP, 1, 0);
  4030. // set the HWNDs
  4031. psinfo->SetHWNDWizard(hwndWizard);
  4032. psinfo->SetHWNDDialog(hDlg);
  4033. psinfo->SetHWNDProgress(hwndProgress);
  4034. psinfo->SetHWNDInputPeak(NULL);
  4035. psinfo->SetHWNDOutputPeak(NULL);
  4036. psinfo->SetHWNDInputVolumeSlider(NULL);
  4037. psinfo->SetHWNDOutputVolumeSlider(NULL);
  4038. // clear the abort flag!
  4039. psinfo->ClearAbortFullDuplex();
  4040. // enable the Back button only
  4041. PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK);
  4042. // init IPC stuff
  4043. hr = psinfo->InitIPC();
  4044. if (FAILED(hr))
  4045. {
  4046. Diagnostics_Write(DVF_ERRORLEVEL, "Unable to Initialize IPC");
  4047. goto error_cleanup;
  4048. }
  4049. // Fire up the full duplex test thread
  4050. hr = psinfo->CreateFullDuplexThread();
  4051. if (FAILED(hr))
  4052. {
  4053. Diagnostics_Write(DVF_ERRORLEVEL, "CreateFullDuplexThread failed, code: %i", hr);
  4054. goto error_cleanup;
  4055. }
  4056. DPF_EXIT();
  4057. return FALSE;
  4058. error_cleanup:
  4059. psinfo->GetHWNDParent(&hwndParent);
  4060. DV_DisplayErrorBox(hr, hwndParent);
  4061. psinfo->SetError(hr);
  4062. psinfo->Abort(hDlg, hr);
  4063. DPF_EXIT();
  4064. return FALSE;
  4065. }
  4066. #undef DPF_MODNAME
  4067. #define DPF_MODNAME "FullDuplexNextHandler"
  4068. BOOL FullDuplexNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4069. {
  4070. DPF_ENTER();
  4071. BOOL fPassed;
  4072. HRESULT hr;
  4073. HWND hwndWizard;
  4074. HWND hwndParent = NULL;
  4075. psinfo->GetFullDuplexResults(&hr);
  4076. switch (hr)
  4077. {
  4078. case DV_HALFDUPLEX:
  4079. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXFAILED);
  4080. Diagnostics_Write(DVF_ERRORLEVEL, "Test resulted in full duplex");
  4081. break;
  4082. case DV_FULLDUPLEX:
  4083. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST);
  4084. Diagnostics_Write(DVF_ERRORLEVEL, "Test resulted in full duplex");
  4085. break;
  4086. case DVERR_SOUNDINITFAILURE:
  4087. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_HALFDUPLEXFAILED);
  4088. Diagnostics_Write(DVF_ERRORLEVEL, "Test encountered unrecoverable error");
  4089. break;
  4090. default:
  4091. // we should not get any other result
  4092. Diagnostics_Write(DVF_ERRORLEVEL, "Unexpected full duplex results, hr: %i", hr);
  4093. goto error_cleanup;
  4094. }
  4095. DPF_EXIT();
  4096. return TRUE;
  4097. error_cleanup:
  4098. psinfo->GetHWNDParent(&hwndParent);
  4099. DV_DisplayErrorBox(hr, hwndParent);
  4100. psinfo->SetError(hr);
  4101. psinfo->Abort(hDlg, hr);
  4102. DPF_EXIT();
  4103. return FALSE;
  4104. }
  4105. #undef DPF_MODNAME
  4106. #define DPF_MODNAME "FullDuplexBackHandler"
  4107. BOOL FullDuplexBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4108. {
  4109. DPF_ENTER();
  4110. HRESULT hr;
  4111. HWND hwndWizard;
  4112. HWND hwndParent = NULL;
  4113. // Get the parent window
  4114. psinfo->GetHWNDWizard(&hwndWizard);
  4115. // shut down the full duplex test
  4116. hr = psinfo->CancelFullDuplexTest();
  4117. if (FAILED(hr) && hr != DVERR_USERCANCEL)
  4118. {
  4119. Diagnostics_Write(DVF_ERRORLEVEL, "CancelFullDuplexTest failed, hr: %i", hr);
  4120. goto error_cleanup;
  4121. }
  4122. // reset the registry to the "test not run" state
  4123. hr = psinfo->SetHalfDuplex(REGVAL_NOTRUN);
  4124. if (FAILED(hr))
  4125. {
  4126. Diagnostics_Write(DVF_ERRORLEVEL, "SetHalfDuplex failed, code: %i", hr);
  4127. }
  4128. hr = psinfo->SetFullDuplex(REGVAL_NOTRUN);
  4129. if (FAILED(hr))
  4130. {
  4131. Diagnostics_Write(DVF_ERRORLEVEL, "SetFullDuplex failed, code: %i", hr);
  4132. }
  4133. hr = psinfo->SetMicDetected(REGVAL_NOTRUN);
  4134. if (FAILED(hr))
  4135. {
  4136. Diagnostics_Write(DVF_ERRORLEVEL, "SetMicDetected failed, code: %i", hr);
  4137. }
  4138. // go back to the welcome page
  4139. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_WELCOME);
  4140. DPF_EXIT();
  4141. return TRUE;
  4142. error_cleanup:
  4143. psinfo->GetHWNDParent(&hwndParent);
  4144. DV_DisplayErrorBox(hr, hwndParent);
  4145. psinfo->SetError(hr);
  4146. psinfo->Abort(hDlg, hr);
  4147. DPF_EXIT();
  4148. return FALSE;
  4149. }
  4150. #undef DPF_MODNAME
  4151. #define DPF_MODNAME "FullDuplexCompleteHandler"
  4152. BOOL FullDuplexCompleteHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4153. {
  4154. DPF_ENTER();
  4155. HWND hwndWizard = NULL;
  4156. HWND hwndParent = NULL;
  4157. HWND hwndProgress;
  4158. LONG lRet;
  4159. HRESULT hr = DV_OK;
  4160. UINT idsErrorMessage = 0;
  4161. // Get the parent window
  4162. psinfo->GetHWNDWizard(&hwndWizard);
  4163. // Disable all the wizard buttons
  4164. PropSheet_SetWizButtons(hwndWizard, 0);
  4165. // Get the progress bar window
  4166. psinfo->GetHWNDProgress(&hwndProgress);
  4167. // Close the full duplex thread handle and get the test results via the exit code
  4168. hr = psinfo->WaitForFullDuplexThreadExitCode();
  4169. switch(hr)
  4170. {
  4171. case DVERR_SOUNDINITFAILURE:
  4172. case DV_HALFDUPLEX:
  4173. case DV_FULLDUPLEX:
  4174. // These are the expected results from the full duplex test thread
  4175. // this means no strange internal error occured, and it is safe
  4176. // to move along to the next part of the wizard.
  4177. // Record the test results
  4178. psinfo->SetFullDuplexResults(hr);
  4179. break;
  4180. case DPNERR_INVALIDDEVICEADDRESS:
  4181. // This can result from no tcp/ip stack on the machine
  4182. // we want to dispaly a special error code and then fall
  4183. // through with the rest of the return codes.
  4184. idsErrorMessage = IDS_ERROR_NODEVICES;
  4185. // fall through
  4186. default:
  4187. // any other error code is not expected and means we hit
  4188. // some internal problem. Bail.
  4189. Diagnostics_Write(DVF_ERRORLEVEL, "Full duplex test thread exited with unexpected error code, hr: %i", hr);
  4190. psinfo->DeinitIPC();
  4191. goto error_cleanup;
  4192. }
  4193. // Deinit the IPC stuff
  4194. hr = psinfo->DeinitIPC();
  4195. if (FAILED(hr))
  4196. {
  4197. Diagnostics_Write(DVF_ERRORLEVEL, "DeinitIPC failed, code: %i", hr);
  4198. goto error_cleanup;
  4199. }
  4200. // Move the progress bar all the way to the end.
  4201. SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 1));
  4202. SendMessage(hwndProgress, PBM_SETPOS, 1, 0);
  4203. // enable and press the next button to move
  4204. // to the next page automatically
  4205. PropSheet_PressButton(hwndWizard, PSBTN_NEXT);
  4206. DPF_EXIT();
  4207. return FALSE;
  4208. error_cleanup:
  4209. psinfo->GetHWNDParent(&hwndParent);
  4210. DV_DisplayErrorBox(hr, hwndParent, idsErrorMessage);
  4211. psinfo->SetError(hr);
  4212. psinfo->Abort(hDlg, hr);
  4213. DPF_EXIT();
  4214. return FALSE;
  4215. }
  4216. #undef DPF_MODNAME
  4217. #define DPF_MODNAME "FullDuplexResetHandler"
  4218. BOOL FullDuplexResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4219. {
  4220. DPF_ENTER();
  4221. DPF_EXIT();
  4222. return FALSE;
  4223. }
  4224. #undef DPF_MODNAME
  4225. #define DPF_MODNAME "MicTestProc"
  4226. INT_PTR CALLBACK MicTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  4227. {
  4228. DPF_ENTER();
  4229. BOOL fRet;
  4230. LPNMHDR lpnm;
  4231. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  4232. fRet = FALSE;
  4233. switch (message)
  4234. {
  4235. case WM_INITDIALOG :
  4236. fRet = MicTestInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  4237. break;
  4238. case WM_NOTIFY :
  4239. lpnm = (LPNMHDR) lParam;
  4240. switch (lpnm->code)
  4241. {
  4242. case PSN_SETACTIVE :
  4243. fRet = MicTestSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  4244. break;
  4245. case PSN_WIZNEXT :
  4246. fRet = MicTestNextHandler(hDlg, message, wParam, lParam, psinfo);
  4247. break;
  4248. case PSN_WIZBACK :
  4249. fRet = MicTestBackHandler(hDlg, message, wParam, lParam, psinfo);
  4250. break;
  4251. case PSN_RESET :
  4252. fRet = MicTestResetHandler(hDlg, message, wParam, lParam, psinfo);
  4253. break;
  4254. default :
  4255. break;
  4256. }
  4257. break;
  4258. case WM_COMMAND:
  4259. switch (LOWORD(wParam))
  4260. {
  4261. case IDC_RECADVANCED:
  4262. fRet = MicTestRecAdvancedHandler(hDlg, message, wParam, lParam, psinfo);
  4263. break;
  4264. default:
  4265. break;
  4266. }
  4267. break;
  4268. case WM_APP_LOOPBACK_RUNNING:
  4269. fRet = MicTestLoopbackRunningHandler(hDlg, message, wParam, lParam, psinfo);
  4270. break;
  4271. case WM_APP_RECORDSTART:
  4272. fRet = MicTestRecordStartHandler(hDlg, message, wParam, lParam, psinfo);
  4273. break;
  4274. case WM_APP_RECORDSTOP:
  4275. fRet = MicTestRecordStopHandler(hDlg, message, wParam, lParam, psinfo);
  4276. break;
  4277. case WM_VSCROLL:
  4278. fRet = MicTestVScrollHandler(hDlg, message, wParam, lParam, psinfo);
  4279. break;
  4280. default:
  4281. break;
  4282. }
  4283. DPF_EXIT();
  4284. return fRet;
  4285. }
  4286. #undef DPF_MODNAME
  4287. #define DPF_MODNAME "MicTestInitDialogHandler"
  4288. BOOL MicTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4289. {
  4290. DPF_ENTER();
  4291. LONG lRet;
  4292. HWND hwndWizard = NULL;
  4293. HWND hwndParent = NULL;
  4294. HWND hwndControl;
  4295. HFONT hfBold;
  4296. HWND hwndRecPeak;
  4297. HWND hwndOutPeak;
  4298. HWND hwndRecSlider;
  4299. HWND hwndOutSlider;
  4300. HWND hwndOutAdvanced;
  4301. HWND hwndOutGroup;
  4302. HRESULT hr = DV_OK;
  4303. // Get the shared data from PROPSHEETPAGE lParam value
  4304. // and load it into GWLP_USERDATA
  4305. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  4306. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  4307. // Get the parent window
  4308. hwndWizard = GetParent(hDlg);
  4309. if (hwndWizard == NULL)
  4310. {
  4311. lRet = GetLastError();
  4312. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  4313. hr = DVERR_GENERIC;
  4314. goto error_cleanup;
  4315. }
  4316. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  4317. if (hwndControl == NULL)
  4318. {
  4319. // error, log it and bail
  4320. lRet = GetLastError();
  4321. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4322. hr = DVERR_GENERIC;
  4323. goto error_cleanup;
  4324. }
  4325. psinfo->GetBoldFont(&hfBold);
  4326. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfBold, (LPARAM)TRUE);
  4327. // Get the peak meter
  4328. hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER);
  4329. if (hwndRecPeak == NULL)
  4330. {
  4331. lRet = GetLastError();
  4332. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4333. hr = DVERR_GENERIC;
  4334. goto error_cleanup;
  4335. }
  4336. // Init the recording peak meter
  4337. SendMessage(hwndRecPeak, PM_SETMIN, 0, 0);
  4338. SendMessage(hwndRecPeak, PM_SETMAX, 0, 99);
  4339. SendMessage(hwndRecPeak, PM_SETCUR, 0, 0);
  4340. // Get the recording volume slider
  4341. hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER);
  4342. if (hwndRecSlider == NULL)
  4343. {
  4344. lRet = GetLastError();
  4345. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4346. hr = DVERR_GENERIC;
  4347. goto error_cleanup;
  4348. }
  4349. // Init the recording volume slider
  4350. SendMessage(hwndRecSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  4351. SendMessage(hwndRecSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN));
  4352. SendMessage(hwndRecSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  4353. SendMessage(hwndRecSlider, TBM_SETTICFREQ,
  4354. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0);
  4355. SendMessage(hwndRecSlider, TBM_SETLINESIZE, 0,
  4356. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20);
  4357. SendMessage(hwndRecSlider, TBM_SETPAGESIZE, 0,
  4358. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5);
  4359. // Get the playback peak meter
  4360. hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER);
  4361. if (hwndOutPeak == NULL)
  4362. {
  4363. lRet = GetLastError();
  4364. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4365. hr = DVERR_GENERIC;
  4366. goto error_cleanup;
  4367. }
  4368. // Init the playback peak meter
  4369. SendMessage(hwndOutPeak, PM_SETMIN, 0, 0);
  4370. SendMessage(hwndOutPeak, PM_SETMAX, 0, 99);
  4371. SendMessage(hwndOutPeak, PM_SETCUR, 0, 0);
  4372. // Get the playback volume slider
  4373. hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER);
  4374. if (hwndOutSlider == NULL)
  4375. {
  4376. lRet = GetLastError();
  4377. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4378. hr = DVERR_GENERIC;
  4379. goto error_cleanup;
  4380. }
  4381. // Init the playback volume slider
  4382. SendMessage(hwndOutSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  4383. SendMessage(hwndOutSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN));
  4384. SendMessage(hwndOutSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  4385. SendMessage(hwndOutSlider, TBM_SETTICFREQ,
  4386. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0);
  4387. SendMessage(hwndOutSlider, TBM_SETLINESIZE, 0,
  4388. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20);
  4389. SendMessage(hwndOutSlider, TBM_SETPAGESIZE, 0,
  4390. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5);
  4391. // grey out all the playback volume stuff
  4392. EnableWindow(hwndOutSlider, FALSE);
  4393. hwndOutAdvanced = GetDlgItem(hDlg, IDC_OUTADVANCED);
  4394. if (hwndOutAdvanced == NULL)
  4395. {
  4396. lRet = GetLastError();
  4397. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4398. hr = DVERR_GENERIC;
  4399. goto error_cleanup;
  4400. }
  4401. EnableWindow(hwndOutAdvanced, FALSE);
  4402. hwndOutGroup = GetDlgItem(hDlg, IDC_OUTGROUP);
  4403. if (hwndOutGroup == NULL)
  4404. {
  4405. lRet = GetLastError();
  4406. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4407. hr = DVERR_GENERIC;
  4408. goto error_cleanup;
  4409. }
  4410. EnableWindow(hwndOutGroup, FALSE);
  4411. DPF_EXIT();
  4412. return FALSE;
  4413. error_cleanup:
  4414. psinfo->GetHWNDParent(&hwndParent);
  4415. DV_DisplayErrorBox(hr, hwndParent);
  4416. psinfo->SetError(hr);
  4417. psinfo->Abort(hDlg, hr);
  4418. DPF_EXIT();
  4419. return FALSE;
  4420. }
  4421. #undef DPF_MODNAME
  4422. #define DPF_MODNAME "MicTestSetActiveHandler"
  4423. BOOL MicTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4424. {
  4425. DPF_ENTER();
  4426. LONG lRet;
  4427. HWND hwndWizard = NULL;
  4428. HWND hwndParent = NULL;
  4429. HWND hwndRecPeak;
  4430. HWND hwndOutPeak;
  4431. HWND hwndRecSlider;
  4432. HWND hwndOutSlider;
  4433. HANDLE hThread;
  4434. HANDLE hEvent;
  4435. DWORD dwThreadId;
  4436. HRESULT hr = DV_OK;
  4437. DWORD dwVolume;
  4438. // Get the parent window
  4439. hwndWizard = GetParent(hDlg);
  4440. if (hwndWizard == NULL)
  4441. {
  4442. lRet = GetLastError();
  4443. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  4444. hr = DVERR_GENERIC;
  4445. goto error_cleanup;
  4446. }
  4447. // Set the recording peak meter to zero
  4448. hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER);
  4449. if (hwndRecPeak == NULL)
  4450. {
  4451. lRet = GetLastError();
  4452. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4453. hr = DVERR_GENERIC;
  4454. goto error_cleanup;
  4455. }
  4456. SendMessage(hwndRecPeak, PM_SETCUR, 0, 0);
  4457. // Get the recording volume control hwnd
  4458. hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER);
  4459. if (hwndRecSlider == NULL)
  4460. {
  4461. lRet = GetLastError();
  4462. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4463. hr = DVERR_GENERIC;
  4464. goto error_cleanup;
  4465. }
  4466. // Set the slider to max
  4467. SendMessage(hwndRecSlider, TBM_SETPOS, 1, SendMessage(hwndRecSlider, TBM_GETRANGEMIN, 0, 0));
  4468. // Set the playback peak meter to zero
  4469. hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER);
  4470. if (hwndOutPeak == NULL)
  4471. {
  4472. lRet = GetLastError();
  4473. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4474. hr = DVERR_GENERIC;
  4475. goto error_cleanup;
  4476. }
  4477. SendMessage(hwndOutPeak, PM_SETCUR, 0, 0);
  4478. // Get the playback volume control hwnd
  4479. hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER);
  4480. if (hwndOutSlider == NULL)
  4481. {
  4482. lRet = GetLastError();
  4483. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4484. hr = DVERR_GENERIC;
  4485. goto error_cleanup;
  4486. }
  4487. // Get the current waveOut volume and set the slider to that position
  4488. hr = psinfo->GetWaveOutVolume(&dwVolume);
  4489. if (FAILED(hr))
  4490. {
  4491. // couldn't get the volume - set the slider to top
  4492. SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMIN, 0, 0));
  4493. }
  4494. else
  4495. {
  4496. SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMAX, 0, 0) - dwVolume);
  4497. }
  4498. // set the HWNDs
  4499. psinfo->SetHWNDWizard(hwndWizard);
  4500. psinfo->SetHWNDDialog(hDlg);
  4501. psinfo->SetHWNDProgress(NULL);
  4502. psinfo->SetHWNDInputPeak(hwndRecPeak);
  4503. psinfo->SetHWNDOutputPeak(hwndOutPeak);
  4504. psinfo->SetHWNDInputVolumeSlider(hwndRecSlider);
  4505. psinfo->SetHWNDOutputVolumeSlider(NULL);
  4506. psinfo->SetLoopbackFlags(0);
  4507. // clear the voice detected flag
  4508. psinfo->ClearVoiceDetected();
  4509. // clear the mic test reg value
  4510. psinfo->SetMicDetected(REGVAL_CRASHED);
  4511. // fire up the loopback test thread
  4512. hr = psinfo->CreateLoopbackThread();
  4513. if (FAILED(hr))
  4514. {
  4515. // error, log it and bail
  4516. Diagnostics_Write(DVF_ERRORLEVEL, "CreateLoopbackThread failed, code: %i", hr);
  4517. goto error_cleanup;
  4518. }
  4519. // disable the buttons - they will be enabled
  4520. // when the loopback test is up and running.
  4521. PropSheet_SetWizButtons(hwndWizard, 0);
  4522. DPF_EXIT();
  4523. return FALSE;
  4524. error_cleanup:
  4525. psinfo->GetHWNDParent(&hwndParent);
  4526. DV_DisplayErrorBox(hr, hwndParent);
  4527. psinfo->SetError(hr);
  4528. psinfo->Abort(hDlg, hr);
  4529. DPF_EXIT();
  4530. return FALSE;
  4531. }
  4532. #undef DPF_MODNAME
  4533. #define DPF_MODNAME "MicTestLoopbackRunningHandler"
  4534. BOOL MicTestLoopbackRunningHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4535. {
  4536. DPF_ENTER();
  4537. LONG lRet;
  4538. HWND hwndWizard = NULL;
  4539. HWND hwndParent = NULL;
  4540. HRESULT hr = DV_OK;
  4541. HWND hwndRecordSlider;
  4542. HWND hwndRecordAdvanced;
  4543. // Get the parent window
  4544. psinfo->GetHWNDWizard(&hwndWizard);
  4545. // lParam is an HRESULT sent by the loopback test thread
  4546. hr = (HRESULT)lParam;
  4547. if (FAILED(hr))
  4548. {
  4549. Diagnostics_Write(DVF_ERRORLEVEL, "LoopbackTestThread signaled error, code: %i", hr);
  4550. goto error_cleanup;
  4551. }
  4552. hwndRecordSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER);
  4553. hwndRecordAdvanced = GetDlgItem( hDlg, IDC_RECADVANCED );
  4554. if( hwndRecordSlider != NULL && hwndRecordAdvanced != NULL )
  4555. {
  4556. DWORD dwDeviceFlags;
  4557. psinfo->GetDeviceFlags( &dwDeviceFlags );
  4558. if( dwDeviceFlags & DVSOUNDCONFIG_NORECVOLAVAILABLE )
  4559. {
  4560. EnableWindow( hwndRecordAdvanced, FALSE );
  4561. EnableWindow( hwndRecordSlider, FALSE );
  4562. }
  4563. }
  4564. else
  4565. {
  4566. hr = DVERR_GENERIC;
  4567. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get record slider window" );
  4568. goto error_cleanup;
  4569. }
  4570. // clear the voice detected flag
  4571. psinfo->ClearVoiceDetected();
  4572. // enable the next button
  4573. PropSheet_SetWizButtons(hwndWizard, PSWIZB_NEXT|PSWIZB_BACK);
  4574. DPF_EXIT();
  4575. return FALSE;
  4576. error_cleanup:
  4577. psinfo->GetHWNDParent(&hwndParent);
  4578. DV_DisplayErrorBox(hr, hwndParent);
  4579. psinfo->SetError(hr);
  4580. psinfo->Abort(hDlg, hr);
  4581. DPF_EXIT();
  4582. return FALSE;
  4583. }
  4584. #undef DPF_MODNAME
  4585. #define DPF_MODNAME "MicTestRecordStartHandler"
  4586. BOOL MicTestRecordStartHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4587. {
  4588. DPF_ENTER();
  4589. // set the voice detected flag
  4590. psinfo->SetVoiceDetected();
  4591. DPF_EXIT();
  4592. return FALSE;
  4593. }
  4594. #undef DPF_MODNAME
  4595. #define DPF_MODNAME "MicTestRecordStopHandler"
  4596. BOOL MicTestRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4597. {
  4598. DPF_ENTER();
  4599. DPF_EXIT();
  4600. return FALSE;
  4601. }
  4602. #undef DPF_MODNAME
  4603. #define DPF_MODNAME "MicTestNextHandler"
  4604. BOOL MicTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4605. {
  4606. DPF_ENTER();
  4607. HRESULT hr;
  4608. HWND hwndWizard;
  4609. HWND hwndSlider;
  4610. BOOL fVoiceDetected;
  4611. // Get the parent window
  4612. psinfo->GetHWNDWizard(&hwndWizard);
  4613. // If we heard a voice, go to the speaker test page.
  4614. // Otherwise, go to the mic failed page
  4615. psinfo->GetVoiceDetected(&fVoiceDetected);
  4616. if (fVoiceDetected)
  4617. {
  4618. // save the current recording slider position
  4619. hwndSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER);
  4620. if (hwndSlider == NULL)
  4621. {
  4622. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", GetLastError());
  4623. }
  4624. else
  4625. {
  4626. psinfo->SetInputVolumeSliderPos((LONG)SendMessage(hwndSlider, TBM_GETPOS, 0, 0));
  4627. }
  4628. // record the mic test result in the registry
  4629. psinfo->SetMicDetected(REGVAL_PASSED);
  4630. // move on to the speaker test.
  4631. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_SPEAKER_TEST);
  4632. }
  4633. else
  4634. {
  4635. hr = psinfo->ShutdownLoopbackThread();
  4636. if (FAILED(hr))
  4637. {
  4638. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr);
  4639. }
  4640. // record the mic test result in the registry
  4641. psinfo->SetMicDetected(REGVAL_FAILED);
  4642. // go to the mic test failed page
  4643. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST_FAILED);
  4644. }
  4645. DPF_EXIT();
  4646. return TRUE;
  4647. }
  4648. #undef DPF_MODNAME
  4649. #define DPF_MODNAME "MicTestBackHandler"
  4650. BOOL MicTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4651. {
  4652. DPF_ENTER();
  4653. HRESULT hr;
  4654. HWND hwndWizard;
  4655. BOOL fVoiceDetected;
  4656. // Get the parent window
  4657. psinfo->GetHWNDWizard(&hwndWizard);
  4658. hr = psinfo->ShutdownLoopbackThread();
  4659. if (FAILED(hr))
  4660. {
  4661. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr);
  4662. }
  4663. // shutdown the any volume controls we launched
  4664. psinfo->CloseWindowsVolumeControl(TRUE);
  4665. psinfo->CloseWindowsVolumeControl(FALSE);
  4666. // make it look like the mic test was never run
  4667. psinfo->SetMicDetected(REGVAL_NOTRUN);
  4668. // go back to the full duplex test page
  4669. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST);
  4670. DPF_EXIT();
  4671. return TRUE;
  4672. }
  4673. #undef DPF_MODNAME
  4674. #define DPF_MODNAME "MicTestVScrollHandler"
  4675. BOOL MicTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4676. {
  4677. DPF_ENTER();
  4678. HWND hwndSlider;
  4679. DWORD dwSliderPos;
  4680. psinfo->GetHWNDInputVolumeSlider(&hwndSlider);
  4681. if (hwndSlider == (HWND)lParam)
  4682. {
  4683. // the user is moving the input slider
  4684. dwSliderPos = (DWORD) SendMessage(hwndSlider, TBM_GETPOS, 0, 0);
  4685. // set the input volume to the user's request
  4686. psinfo->SetRecordVolume(AmpFactorToDB(DBToAmpFactor(DSBVOLUME_MAX)-dwSliderPos));
  4687. }
  4688. DPF_EXIT();
  4689. return FALSE;
  4690. }
  4691. #undef DPF_MODNAME
  4692. #define DPF_MODNAME "MicTestRecAdvancedHandler"
  4693. BOOL MicTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4694. {
  4695. DPF_ENTER();
  4696. HWND hwndWizard = GetParent(hDlg);
  4697. if (hwndWizard == NULL)
  4698. {
  4699. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed");
  4700. DPF_EXIT();
  4701. return FALSE;
  4702. }
  4703. psinfo->LaunchWindowsVolumeControl(hwndWizard, TRUE);
  4704. DPF_EXIT();
  4705. return FALSE;
  4706. }
  4707. #undef DPF_MODNAME
  4708. #define DPF_MODNAME "LoopbackTestThreadProc"
  4709. DWORD WINAPI LoopbackTestThreadProc(LPVOID lpvParam)
  4710. {
  4711. DPF_ENTER();
  4712. CSupervisorInfo* psinfo;
  4713. HRESULT hr;
  4714. LONG lRet;
  4715. HWND hwnd;
  4716. LPDIRECTPLAYVOICESERVER lpdpvs;
  4717. LPDIRECTPLAYVOICECLIENT lpdpvc;
  4718. PDIRECTPLAY8SERVER lpdp8;
  4719. DWORD dwRet;
  4720. HANDLE hEvent;
  4721. DWORD dwWaveOutId;
  4722. DWORD dwWaveInId;
  4723. HWND hwndWizard;
  4724. GUID guidCaptureDevice;
  4725. GUID guidRenderDevice;
  4726. DWORD dwFlags;
  4727. DWORD dwSize;
  4728. PDVSOUNDDEVICECONFIG pdvsdc = NULL;
  4729. PBYTE pdvsdcBuffer = NULL;
  4730. BOOL fLoopbackStarted = FALSE;
  4731. psinfo = (CSupervisorInfo*)lpvParam;
  4732. psinfo->GetHWNDDialog(&hwnd);
  4733. psinfo->GetHWNDWizard(&hwndWizard);
  4734. psinfo->GetCaptureDevice(&guidCaptureDevice);
  4735. psinfo->GetRenderDevice(&guidRenderDevice);
  4736. psinfo->GetLoopbackFlags(&dwFlags);
  4737. lpdpvs = NULL;
  4738. lpdpvc = NULL;
  4739. lpdp8 = NULL;
  4740. // new thread, init COM
  4741. hr = COM_CoInitialize(NULL);
  4742. if( FAILED( hr ) )
  4743. {
  4744. Diagnostics_Write(DVF_ERRORLEVEL, "COM_CoInitialize failed, code: %i", hr);
  4745. if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr))
  4746. {
  4747. lRet = GetLastError();
  4748. Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet);
  4749. }
  4750. goto error_cleanup;
  4751. }
  4752. hr = StartDirectPlay( &lpdp8 );
  4753. if( FAILED( hr ) )
  4754. {
  4755. Diagnostics_Write(DVF_ERRORLEVEL, "StartDirectPlay failed, code: 0x%x", hr);
  4756. goto error_cleanup;
  4757. }
  4758. hr = StartLoopback(
  4759. &lpdpvs,
  4760. &lpdpvc,
  4761. &lpdp8,
  4762. (LPVOID)psinfo,
  4763. hwndWizard,
  4764. guidCaptureDevice,
  4765. guidRenderDevice,
  4766. dwFlags);
  4767. if (FAILED(hr) )
  4768. {
  4769. Diagnostics_Write(DVF_ERRORLEVEL, "StartLoopback failed, code: %i", hr);
  4770. if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr))
  4771. {
  4772. lRet = GetLastError();
  4773. Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet);
  4774. }
  4775. goto error_cleanup;
  4776. }
  4777. psinfo->SetLoopbackRunning( TRUE );
  4778. if( !(dwFlags & DVSOUNDCONFIG_HALFDUPLEX) && hr == DV_HALFDUPLEX )
  4779. {
  4780. Diagnostics_Write(DVF_ERRORLEVEL, "StartLoopback failed with half duplex when expecting full duplex", hr);
  4781. if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr))
  4782. {
  4783. lRet = GetLastError();
  4784. Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet);
  4785. }
  4786. goto error_cleanup;
  4787. }
  4788. // save the voice client interface for the other threads to play with
  4789. psinfo->SetDPVC(lpdpvc);
  4790. dwSize = 0;
  4791. hr = lpdpvc->GetSoundDeviceConfig(pdvsdc, &dwSize);
  4792. if( hr != DVERR_BUFFERTOOSMALL )
  4793. {
  4794. DPFX(DPFPREP, DVF_ERRORLEVEL, "GetSoundDeviceConfig failed, hr: %i", hr );
  4795. if (!FAILED(hr))
  4796. {
  4797. // map success codes to a generic failure, since we
  4798. // did not expect success
  4799. hr = DVERR_GENERIC;
  4800. }
  4801. goto error_cleanup;
  4802. }
  4803. pdvsdcBuffer = new BYTE[dwSize];
  4804. if( pdvsdcBuffer == NULL )
  4805. {
  4806. DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory alloc failure" );
  4807. hr = DVERR_OUTOFMEMORY;
  4808. goto error_cleanup;
  4809. }
  4810. pdvsdc = (PDVSOUNDDEVICECONFIG) pdvsdcBuffer;
  4811. pdvsdc->dwSize = sizeof( DVSOUNDDEVICECONFIG );
  4812. hr = lpdpvc->GetSoundDeviceConfig(pdvsdc, &dwSize);
  4813. if (FAILED(hr))
  4814. {
  4815. Diagnostics_Write(DVF_ERRORLEVEL, "GetSoundDeviceConfig failed, hr: %i", hr);
  4816. goto error_cleanup;
  4817. }
  4818. hr = DV_MapGUIDToWaveID(FALSE, pdvsdc->guidPlaybackDevice, &dwWaveOutId);
  4819. if (FAILED(hr))
  4820. {
  4821. Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapGUIDToWaveID failed, hr: %i", hr);
  4822. goto error_cleanup;
  4823. }
  4824. hr = psinfo->SetWaveOutId(dwWaveOutId);
  4825. if (FAILED(hr))
  4826. {
  4827. Diagnostics_Write(DVF_ERRORLEVEL, "SetWaveOutId failed, hr: %i", hr);
  4828. goto error_cleanup;
  4829. }
  4830. hr = DV_MapGUIDToWaveID(TRUE, pdvsdc->guidCaptureDevice, &dwWaveInId);
  4831. if (FAILED(hr))
  4832. {
  4833. Diagnostics_Write(DVF_ERRORLEVEL, "DV_MapGUIDToWaveID failed, hr: %i", hr);
  4834. goto error_cleanup;
  4835. }
  4836. psinfo->SetWaveInId(dwWaveInId);
  4837. psinfo->SetDeviceFlags( pdvsdc->dwFlags );
  4838. // inform the app that loopback is up and running.
  4839. hr = DV_OK;
  4840. // Also send along the flags from GetSoundDeviceConfig
  4841. if (!PostMessage(hwnd, WM_APP_LOOPBACK_RUNNING, 0, (LPARAM)hr))
  4842. {
  4843. lRet = GetLastError();
  4844. Diagnostics_Write(DVF_ERRORLEVEL, "PostMessage failed, code: %i", lRet);
  4845. goto error_cleanup;
  4846. }
  4847. // wait on the shutdown event
  4848. hr = psinfo->WaitForLoopbackShutdownEvent();
  4849. if (FAILED(hr))
  4850. {
  4851. Diagnostics_Write(DVF_ERRORLEVEL, "WaitForLoopbackShutdown failed, code: %i", hr);
  4852. goto error_cleanup;
  4853. }
  4854. psinfo->SetLoopbackRunning( FALSE);
  4855. delete [] pdvsdcBuffer;
  4856. pdvsdcBuffer = NULL;
  4857. // Null out the interface pointer in sinfo
  4858. psinfo->SetDPVC(NULL);
  4859. // shutdown the loopback test
  4860. hr = StopLoopback(lpdpvs, lpdpvc, lpdp8);
  4861. if (FAILED(hr))
  4862. {
  4863. Diagnostics_Write(DVF_ERRORLEVEL, "StopLoopback failed, code: %i", hr);
  4864. goto error_cleanup;
  4865. }
  4866. hr = StopDirectPlay( lpdp8 );
  4867. lpdp8 = NULL;
  4868. if( FAILED( hr ) )
  4869. {
  4870. Diagnostics_Write(DVF_ERRORLEVEL, "StopDirectPlay failed, code: %i", hr);
  4871. goto error_cleanup;
  4872. }
  4873. // Signal the loopback thread exit event
  4874. psinfo->SignalLoopbackThreadDone();
  4875. COM_CoUninitialize();
  4876. DPF_EXIT();
  4877. return DV_OK;
  4878. error_cleanup:
  4879. if (pdvsdcBuffer != NULL)
  4880. {
  4881. delete [] pdvsdcBuffer;
  4882. }
  4883. if (fLoopbackStarted)
  4884. {
  4885. StopLoopback(lpdpvs, lpdpvc, lpdp8);
  4886. }
  4887. if( lpdp8 )
  4888. {
  4889. StopDirectPlay( lpdp8 );
  4890. }
  4891. psinfo->SetLoopbackRunning( FALSE);
  4892. psinfo->SignalLoopbackThreadDone();
  4893. COM_CoUninitialize();
  4894. DPF_EXIT();
  4895. return hr;
  4896. }
  4897. #undef DPF_MODNAME
  4898. #define DPF_MODNAME "MicTestResetHandler"
  4899. BOOL MicTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4900. {
  4901. DPF_ENTER();
  4902. DPF_EXIT();
  4903. return FALSE;
  4904. }
  4905. #undef DPF_MODNAME
  4906. #define DPF_MODNAME "CompleteProc"
  4907. INT_PTR CALLBACK CompleteProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  4908. {
  4909. DPF_ENTER();
  4910. BOOL fRet;
  4911. LPNMHDR lpnm;
  4912. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  4913. fRet = FALSE;
  4914. switch (message)
  4915. {
  4916. case WM_INITDIALOG :
  4917. fRet = CompleteInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  4918. break;
  4919. case WM_NOTIFY :
  4920. lpnm = (LPNMHDR) lParam;
  4921. switch (lpnm->code)
  4922. {
  4923. case PSN_SETACTIVE :
  4924. fRet = CompleteSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  4925. break;
  4926. case PSN_WIZFINISH :
  4927. fRet = CompleteFinishHandler(hDlg, message, wParam, lParam, psinfo);
  4928. break;
  4929. case PSN_RESET :
  4930. fRet = CompleteResetHandler(hDlg, message, wParam, lParam, psinfo);
  4931. break;
  4932. default :
  4933. break;
  4934. }
  4935. break;
  4936. default:
  4937. break;
  4938. }
  4939. DPF_EXIT();
  4940. return fRet;
  4941. }
  4942. #undef DPF_MODNAME
  4943. #define DPF_MODNAME "CompleteInitDialogHandler"
  4944. BOOL CompleteInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4945. {
  4946. DPF_ENTER();
  4947. LONG lRet;
  4948. HWND hwndWizard = NULL;
  4949. HWND hwndParent = NULL;
  4950. HWND hwndControl;
  4951. HFONT hfTitle;
  4952. HRESULT hr = DV_OK;
  4953. // Get the shared data from PROPSHEETPAGE lParam value
  4954. // and load it into GWLP_USERDATA
  4955. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  4956. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  4957. // Get the parent window
  4958. hwndWizard = GetParent(hDlg);
  4959. if (hwndWizard == NULL)
  4960. {
  4961. lRet = GetLastError();
  4962. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  4963. hr = DVERR_GENERIC;
  4964. goto error_cleanup;
  4965. }
  4966. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  4967. if (hwndControl == NULL)
  4968. {
  4969. // error, log it and bail
  4970. lRet = GetLastError();
  4971. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  4972. hr = DVERR_GENERIC;
  4973. goto error_cleanup;
  4974. }
  4975. psinfo->GetTitleFont(&hfTitle);
  4976. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE);
  4977. DPF_EXIT();
  4978. return FALSE;
  4979. error_cleanup:
  4980. psinfo->GetHWNDParent(&hwndParent);
  4981. DV_DisplayErrorBox(hr, hwndParent);
  4982. psinfo->SetError(hr);
  4983. psinfo->Abort(hDlg, hr);
  4984. DPF_EXIT();
  4985. return FALSE;
  4986. }
  4987. #undef DPF_MODNAME
  4988. #define DPF_MODNAME "CompleteSetActiveHandler"
  4989. BOOL CompleteSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  4990. {
  4991. DPF_ENTER();
  4992. LONG lRet;
  4993. HWND hwndWizard;
  4994. HWND hwndParent = NULL;
  4995. HANDLE hEvent;
  4996. HRESULT hr;
  4997. // Get the parent window
  4998. hwndWizard = GetParent(hDlg);
  4999. if (hwndWizard == NULL)
  5000. {
  5001. // log it, and return, don't know how to terminate the wizard properly
  5002. // without this handle!
  5003. lRet = GetLastError();
  5004. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5005. hr = DVERR_GENERIC;
  5006. goto error_cleanup;
  5007. }
  5008. // set the HWNDs
  5009. psinfo->SetHWNDWizard(hwndWizard);
  5010. psinfo->SetHWNDDialog(hDlg);
  5011. psinfo->SetHWNDProgress(NULL);
  5012. psinfo->SetHWNDInputPeak(NULL);
  5013. psinfo->SetHWNDOutputPeak(NULL);
  5014. psinfo->SetHWNDInputVolumeSlider(NULL);
  5015. psinfo->SetHWNDOutputVolumeSlider(NULL);
  5016. PropSheet_SetWizButtons(hwndWizard, PSWIZB_FINISH);
  5017. DPF_EXIT();
  5018. return FALSE;
  5019. error_cleanup:
  5020. psinfo->GetHWNDParent(&hwndParent);
  5021. DV_DisplayErrorBox(hr, hwndParent);
  5022. psinfo->SetError(hr);
  5023. psinfo->Abort(hDlg, hr);
  5024. DPF_EXIT();
  5025. return FALSE;
  5026. }
  5027. #undef DPF_MODNAME
  5028. #define DPF_MODNAME "CompleteFinishHandler"
  5029. BOOL CompleteFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5030. {
  5031. DPF_ENTER();
  5032. psinfo->Finish();
  5033. DPF_EXIT();
  5034. return FALSE;
  5035. }
  5036. #undef DPF_MODNAME
  5037. #define DPF_MODNAME "CompleteResetHandler"
  5038. BOOL CompleteResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5039. {
  5040. DPF_ENTER();
  5041. DPF_EXIT();
  5042. return FALSE;
  5043. }
  5044. #undef DPF_MODNAME
  5045. #define DPF_MODNAME "MicTestFailedProc"
  5046. INT_PTR CALLBACK MicTestFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  5047. {
  5048. DPF_ENTER();
  5049. LONG lRet;
  5050. BOOL fRet;
  5051. LPNMHDR lpnm;
  5052. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  5053. fRet = FALSE;
  5054. switch (message)
  5055. {
  5056. case WM_INITDIALOG :
  5057. MicTestFailedInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  5058. break;
  5059. case WM_NOTIFY :
  5060. lpnm = (LPNMHDR) lParam;
  5061. switch (lpnm->code)
  5062. {
  5063. case PSN_SETACTIVE :
  5064. fRet = MicTestFailedSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  5065. break;
  5066. case PSN_WIZBACK :
  5067. fRet = MicTestFailedBackHandler(hDlg, message, wParam, lParam, psinfo);
  5068. break;
  5069. case PSN_RESET :
  5070. fRet = MicTestFailedResetHandler(hDlg, message, wParam, lParam, psinfo);
  5071. break;
  5072. case PSN_WIZFINISH :
  5073. fRet = MicTestFailedFinishHandler(hDlg, message, wParam, lParam, psinfo);
  5074. break;
  5075. default :
  5076. break;
  5077. }
  5078. break;
  5079. default:
  5080. break;
  5081. }
  5082. DPF_EXIT();
  5083. return fRet;
  5084. }
  5085. #undef DPF_MODNAME
  5086. #define DPF_MODNAME "MicTestFailedInitDialogHandler"
  5087. BOOL MicTestFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5088. {
  5089. DPF_ENTER();
  5090. LONG lRet;
  5091. HWND hwndWizard = NULL;
  5092. HWND hwndParent = NULL;
  5093. HWND hwndControl;
  5094. HFONT hfTitle;
  5095. HICON hIcon;
  5096. HRESULT hr = DV_OK;
  5097. // Get the shared data from PROPSHEETPAGE lParam value
  5098. // and load it into GWLP_USERDATA
  5099. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  5100. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  5101. // Get the parent window
  5102. hwndWizard = GetParent(hDlg);
  5103. if (hwndWizard == NULL)
  5104. {
  5105. lRet = GetLastError();
  5106. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5107. hr = DVERR_GENERIC;
  5108. goto error_cleanup;
  5109. }
  5110. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  5111. if (hwndControl == NULL)
  5112. {
  5113. // error, log it and bail
  5114. lRet = GetLastError();
  5115. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5116. hr = DVERR_GENERIC;
  5117. goto error_cleanup;
  5118. }
  5119. psinfo->GetTitleFont(&hfTitle);
  5120. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE);
  5121. // load the warning icon
  5122. hIcon = LoadIcon(NULL, IDI_WARNING);
  5123. SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
  5124. DPF_EXIT();
  5125. return FALSE;
  5126. // error block
  5127. error_cleanup:
  5128. psinfo->GetHWNDParent(&hwndParent);
  5129. DV_DisplayErrorBox(hr, hwndParent);
  5130. psinfo->SetError(hr);
  5131. psinfo->Abort(hDlg, hr);
  5132. DPF_EXIT();
  5133. return FALSE;
  5134. }
  5135. #undef DPF_MODNAME
  5136. #define DPF_MODNAME "MicTestFailedSetActiveHandler"
  5137. BOOL MicTestFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5138. {
  5139. DPF_ENTER();
  5140. LONG lRet;
  5141. HWND hwndWizard;
  5142. HWND hwndParent = NULL;
  5143. HWND hwndPeak;
  5144. HANDLE hEvent;
  5145. HRESULT hr;
  5146. PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC );
  5147. // Get the parent window
  5148. hwndWizard = GetParent(hDlg);
  5149. if (hwndWizard == NULL)
  5150. {
  5151. // log it, and return, don't know how to terminate the wizard properly
  5152. // without this handle!
  5153. lRet = GetLastError();
  5154. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5155. hr = DVERR_GENERIC;
  5156. goto error_cleanup;
  5157. }
  5158. // set the HWNDs
  5159. psinfo->SetHWNDWizard(hwndWizard);
  5160. psinfo->SetHWNDDialog(hDlg);
  5161. psinfo->SetHWNDProgress(NULL);
  5162. psinfo->SetHWNDInputPeak(NULL);
  5163. psinfo->SetHWNDOutputPeak(NULL);
  5164. psinfo->SetHWNDInputVolumeSlider(NULL);
  5165. psinfo->SetHWNDOutputVolumeSlider(NULL);
  5166. // enable the finish and back buttons
  5167. PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_FINISH);
  5168. DPF_EXIT();
  5169. return FALSE;
  5170. error_cleanup:
  5171. psinfo->GetHWNDParent(&hwndParent);
  5172. DV_DisplayErrorBox(hr, hwndParent);
  5173. psinfo->SetError(hr);
  5174. psinfo->Abort(hDlg, hr);
  5175. DPF_EXIT();
  5176. return FALSE;
  5177. }
  5178. #undef DPF_MODNAME
  5179. #define DPF_MODNAME "MicTestFailedRecordStopHandler"
  5180. BOOL MicTestFailedRecordStopHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5181. {
  5182. DPF_ENTER();
  5183. DPF_EXIT();
  5184. return FALSE;
  5185. }
  5186. #undef DPF_MODNAME
  5187. #define DPF_MODNAME "MicTestFailedBackHandler"
  5188. BOOL MicTestFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5189. {
  5190. DPF_ENTER();
  5191. // go back to the mic test page
  5192. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST);
  5193. DPF_EXIT();
  5194. return TRUE;
  5195. }
  5196. #undef DPF_MODNAME
  5197. #define DPF_MODNAME "MicTestFailedResetHandler"
  5198. BOOL MicTestFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5199. {
  5200. DPF_ENTER();
  5201. DPF_EXIT();
  5202. return FALSE;
  5203. }
  5204. #undef DPF_MODNAME
  5205. #define DPF_MODNAME "MicTestFailedFinishHandler"
  5206. BOOL MicTestFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5207. {
  5208. DPF_ENTER();
  5209. psinfo->Finish();
  5210. DPF_EXIT();
  5211. return FALSE;
  5212. }
  5213. #undef DPF_MODNAME
  5214. #define DPF_MODNAME "SpeakerTestProc"
  5215. INT_PTR CALLBACK SpeakerTestProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  5216. {
  5217. DPF_ENTER();
  5218. LONG lRet;
  5219. BOOL fRet;
  5220. LPNMHDR lpnm;
  5221. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  5222. fRet = FALSE;
  5223. switch (message)
  5224. {
  5225. case WM_INITDIALOG :
  5226. SpeakerTestInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  5227. break;
  5228. case WM_NOTIFY :
  5229. lpnm = (LPNMHDR) lParam;
  5230. switch (lpnm->code)
  5231. {
  5232. case PSN_SETACTIVE :
  5233. fRet = SpeakerTestSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  5234. break;
  5235. case PSN_WIZNEXT :
  5236. fRet = SpeakerTestNextHandler(hDlg, message, wParam, lParam, psinfo);
  5237. break;
  5238. case PSN_WIZBACK :
  5239. fRet = SpeakerTestBackHandler(hDlg, message, wParam, lParam, psinfo);
  5240. break;
  5241. case PSN_RESET :
  5242. fRet = SpeakerTestResetHandler(hDlg, message, wParam, lParam, psinfo);
  5243. break;
  5244. default :
  5245. break;
  5246. }
  5247. break;
  5248. case WM_COMMAND:
  5249. switch (LOWORD(wParam))
  5250. {
  5251. case IDC_RECADVANCED:
  5252. fRet = SpeakerTestRecAdvancedHandler(hDlg, message, wParam, lParam, psinfo);
  5253. break;
  5254. case IDC_OUTADVANCED:
  5255. fRet = SpeakerTestOutAdvancedHandler(hDlg, message, wParam, lParam, psinfo);
  5256. break;
  5257. default:
  5258. break;
  5259. }
  5260. break;
  5261. case WM_VSCROLL:
  5262. fRet = SpeakerTestVScrollHandler(hDlg, message, wParam, lParam, psinfo);
  5263. break;
  5264. default:
  5265. break;
  5266. }
  5267. DPF_ENTER();
  5268. return fRet;
  5269. }
  5270. #undef DPF_MODNAME
  5271. #define DPF_MODNAME "SpeakerTestInitDialogHandler"
  5272. BOOL SpeakerTestInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5273. {
  5274. DPF_ENTER();
  5275. LONG lRet;
  5276. HWND hwndWizard = NULL;
  5277. HWND hwndParent = NULL;
  5278. HWND hwndControl;
  5279. HFONT hfBold;
  5280. HWND hwndRecPeak;
  5281. HWND hwndOutPeak;
  5282. HWND hwndRecSlider;
  5283. HWND hwndOutSlider;
  5284. HRESULT hr = DV_OK;
  5285. // Get the shared data from PROPSHEETPAGE lParam value
  5286. // and load it into GWLP_USERDATA
  5287. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  5288. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  5289. // Get the parent window
  5290. hwndWizard = GetParent(hDlg);
  5291. if (hwndWizard == NULL)
  5292. {
  5293. lRet = GetLastError();
  5294. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5295. hr = DVERR_GENERIC;
  5296. goto error_cleanup;
  5297. }
  5298. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  5299. if (hwndControl == NULL)
  5300. {
  5301. // error, log it and bail
  5302. lRet = GetLastError();
  5303. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5304. hr = DVERR_GENERIC;
  5305. goto error_cleanup;
  5306. }
  5307. psinfo->GetBoldFont(&hfBold);
  5308. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfBold, (LPARAM)TRUE);
  5309. // Init the recording peak meter
  5310. hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER);
  5311. if (hwndRecPeak == NULL)
  5312. {
  5313. lRet = GetLastError();
  5314. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5315. hr = DVERR_GENERIC;
  5316. goto error_cleanup;
  5317. }
  5318. SendMessage(hwndRecPeak, PM_SETMIN, 0, 0);
  5319. SendMessage(hwndRecPeak, PM_SETMAX, 0, 99);
  5320. SendMessage(hwndRecPeak, PM_SETCUR, 0, 0);
  5321. // Init the recording volume slider
  5322. hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER);
  5323. if (hwndRecSlider == NULL)
  5324. {
  5325. lRet = GetLastError();
  5326. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5327. hr = DVERR_GENERIC;
  5328. goto error_cleanup;
  5329. }
  5330. SendMessage(hwndRecSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  5331. SendMessage(hwndRecSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN));
  5332. SendMessage(hwndRecSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  5333. SendMessage(hwndRecSlider, TBM_SETTICFREQ,
  5334. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0);
  5335. SendMessage(hwndRecSlider, TBM_SETLINESIZE, 0,
  5336. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20);
  5337. SendMessage(hwndRecSlider, TBM_SETPAGESIZE, 0,
  5338. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5);
  5339. // Init the playback peak meter
  5340. hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER);
  5341. if (hwndOutPeak == NULL)
  5342. {
  5343. lRet = GetLastError();
  5344. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5345. hr = DVERR_GENERIC;
  5346. goto error_cleanup;
  5347. }
  5348. SendMessage(hwndOutPeak, PM_SETMIN, 0, 0);
  5349. SendMessage(hwndOutPeak, PM_SETMAX, 0, 99);
  5350. SendMessage(hwndOutPeak, PM_SETCUR, 0, 0);
  5351. // Init the playback volume slider
  5352. hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER);
  5353. if (hwndOutSlider == NULL)
  5354. {
  5355. lRet = GetLastError();
  5356. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5357. hr = DVERR_GENERIC;
  5358. goto error_cleanup;
  5359. }
  5360. SendMessage(hwndOutSlider, TBM_SETRANGEMIN, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  5361. SendMessage(hwndOutSlider, TBM_SETRANGEMAX, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN));
  5362. SendMessage(hwndOutSlider, TBM_SETPOS, 0, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  5363. SendMessage(hwndOutSlider, TBM_SETTICFREQ,
  5364. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/10, 0);
  5365. SendMessage(hwndOutSlider, TBM_SETLINESIZE, 0,
  5366. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/20);
  5367. SendMessage(hwndOutSlider, TBM_SETPAGESIZE, 0,
  5368. (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN))/5);
  5369. DPF_EXIT();
  5370. return FALSE;
  5371. error_cleanup:
  5372. psinfo->GetHWNDParent(&hwndParent);
  5373. DV_DisplayErrorBox(hr, hwndParent);
  5374. psinfo->SetError(hr);
  5375. psinfo->Abort(hDlg, hr);
  5376. DPF_EXIT();
  5377. return FALSE;
  5378. }
  5379. #undef DPF_MODNAME
  5380. #define DPF_MODNAME "SpeakerTestSetActiveHandler"
  5381. BOOL SpeakerTestSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5382. {
  5383. DPF_ENTER();
  5384. LONG lRet;
  5385. HWND hwndWizard = NULL;
  5386. HWND hwndParent = NULL;
  5387. HWND hwndRecPeak;
  5388. HWND hwndOutPeak;
  5389. HWND hwndRecSlider;
  5390. HWND hwndOutSlider;
  5391. HANDLE hEvent;
  5392. HRESULT hr = DV_OK;
  5393. DWORD dwVolume;
  5394. HWND hwndRecAdvanced;
  5395. // Get the parent window
  5396. hwndWizard = GetParent(hDlg);
  5397. if (hwndWizard == NULL)
  5398. {
  5399. lRet = GetLastError();
  5400. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5401. hr = DVERR_GENERIC;
  5402. goto error_cleanup;
  5403. }
  5404. // Reset the recording peak meter
  5405. hwndRecPeak = GetDlgItem(hDlg, IDC_RECPEAKMETER);
  5406. if (hwndRecPeak == NULL)
  5407. {
  5408. lRet = GetLastError();
  5409. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5410. hr = DVERR_GENERIC;
  5411. goto error_cleanup;
  5412. }
  5413. SendMessage(hwndRecPeak, PM_SETCUR, 0, 0);
  5414. // set the recording volume slider to match
  5415. // the recording volume slider from the mic
  5416. // test page.
  5417. hwndRecSlider = GetDlgItem(hDlg, IDC_RECVOL_SLIDER);
  5418. if (hwndRecSlider == NULL)
  5419. {
  5420. lRet = GetLastError();
  5421. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5422. hr = DVERR_GENERIC;
  5423. goto error_cleanup;
  5424. }
  5425. hwndRecAdvanced = GetDlgItem( hDlg, IDC_RECADVANCED );
  5426. if (hwndRecAdvanced == NULL)
  5427. {
  5428. lRet = GetLastError();
  5429. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5430. hr = lRet;
  5431. goto error_cleanup;
  5432. }
  5433. DWORD dwDeviceFlags;
  5434. psinfo->GetDeviceFlags( &dwDeviceFlags );
  5435. if( dwDeviceFlags & DVSOUNDCONFIG_NORECVOLAVAILABLE )
  5436. {
  5437. EnableWindow( hwndRecSlider, FALSE );
  5438. EnableWindow( hwndRecAdvanced, FALSE );
  5439. }
  5440. LONG lPos;
  5441. psinfo->GetInputVolumeSliderPos(&lPos);
  5442. SendMessage(hwndRecSlider, TBM_SETPOS, 1, lPos);
  5443. // Reset the playback peak meter
  5444. hwndOutPeak = GetDlgItem(hDlg, IDC_OUTPEAKMETER);
  5445. if (hwndOutPeak == NULL)
  5446. {
  5447. lRet = GetLastError();
  5448. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5449. hr = DVERR_GENERIC;
  5450. goto error_cleanup;
  5451. }
  5452. SendMessage(hwndOutPeak, PM_SETCUR, 0, 0);
  5453. // Grey out the playback volume slider - until we come back
  5454. // to fix it
  5455. hwndOutSlider = GetDlgItem(hDlg, IDC_OUTVOL_SLIDER);
  5456. if (hwndOutSlider == NULL)
  5457. {
  5458. lRet = GetLastError();
  5459. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5460. hr = DVERR_GENERIC;
  5461. goto error_cleanup;
  5462. }
  5463. // Get the current waveOut volume and set the slider to that position
  5464. hr = psinfo->GetWaveOutVolume(&dwVolume);
  5465. if (FAILED(hr))
  5466. {
  5467. // couldn't get the volume - set the slider to top
  5468. SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMIN, 0, 0));
  5469. // disable the slider
  5470. EnableWindow(hwndOutSlider, FALSE);
  5471. }
  5472. else
  5473. {
  5474. SendMessage(hwndOutSlider, TBM_SETPOS, 1, SendMessage(hwndOutSlider, TBM_GETRANGEMAX, 0, 0) - dwVolume);
  5475. }
  5476. // set the HWNDs
  5477. psinfo->SetHWNDWizard(hwndWizard);
  5478. psinfo->SetHWNDDialog(hDlg);
  5479. psinfo->SetHWNDProgress(NULL);
  5480. psinfo->SetHWNDInputPeak(hwndRecPeak);
  5481. psinfo->SetHWNDOutputPeak(hwndOutPeak);
  5482. psinfo->SetHWNDInputVolumeSlider(hwndRecSlider);
  5483. psinfo->SetHWNDOutputVolumeSlider(hwndOutSlider);
  5484. // unmute the output
  5485. hr = psinfo->Unmute();
  5486. if (FAILED(hr))
  5487. {
  5488. Diagnostics_Write(DVF_ERRORLEVEL, "Unmute failed, code: %i", hr);
  5489. goto error_cleanup;
  5490. }
  5491. // enable the next button
  5492. PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_NEXT);
  5493. DPF_EXIT();
  5494. return FALSE;
  5495. error_cleanup:
  5496. psinfo->GetHWNDParent(&hwndParent);
  5497. DV_DisplayErrorBox(hr, hwndParent);
  5498. psinfo->SetError(hr);
  5499. psinfo->Abort(hDlg, hr);
  5500. DPF_EXIT();
  5501. return FALSE;
  5502. }
  5503. #undef DPF_MODNAME
  5504. #define DPF_MODNAME "SpeakerTestNextHandler"
  5505. BOOL SpeakerTestNextHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5506. {
  5507. DPF_ENTER();
  5508. HRESULT hr = DV_OK;
  5509. HWND hwndWizard = NULL;
  5510. HWND hwndParent = NULL;
  5511. // get the parent window
  5512. psinfo->GetHWNDWizard(&hwndWizard);
  5513. // shutdown the loopback test
  5514. hr = psinfo->ShutdownLoopbackThread();
  5515. if (FAILED(hr))
  5516. {
  5517. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, code: %i", hr);
  5518. goto error_cleanup;
  5519. }
  5520. // close any volume controls that are open.
  5521. psinfo->CloseWindowsVolumeControl(TRUE);
  5522. psinfo->CloseWindowsVolumeControl(FALSE);
  5523. // the next page is the completion page
  5524. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_COMPLETE);
  5525. DPF_EXIT();
  5526. return TRUE;
  5527. error_cleanup:
  5528. psinfo->GetHWNDParent(&hwndParent);
  5529. DV_DisplayErrorBox(hr, hwndParent);
  5530. psinfo->SetError(hr);
  5531. psinfo->Abort(hDlg, hr);
  5532. DPF_EXIT();
  5533. return FALSE;
  5534. }
  5535. #undef DPF_MODNAME
  5536. #define DPF_MODNAME "SpeakerTestBackHandler"
  5537. BOOL SpeakerTestBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5538. {
  5539. DPF_ENTER();
  5540. HRESULT hr = DV_OK;
  5541. HWND hwndWizard = NULL;
  5542. HWND hwndParent = NULL;
  5543. // get the parent window
  5544. psinfo->GetHWNDWizard(&hwndWizard);
  5545. // shutdown the loopback test, so the mic test
  5546. // page can start fresh.
  5547. hr = psinfo->ShutdownLoopbackThread();
  5548. if (FAILED(hr))
  5549. {
  5550. Diagnostics_Write(DVF_ERRORLEVEL, "ShutdownLoopbackThread failed, hr: %i", hr);
  5551. goto error_cleanup;
  5552. }
  5553. // close the output volume control, if showing
  5554. psinfo->CloseWindowsVolumeControl(FALSE);
  5555. // go back to the mic test page
  5556. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_MICTEST);
  5557. DPF_EXIT();
  5558. return TRUE;
  5559. error_cleanup:
  5560. psinfo->GetHWNDParent(&hwndParent);
  5561. DV_DisplayErrorBox(hr, hwndParent);
  5562. psinfo->SetError(hr);
  5563. psinfo->Abort(hDlg, hr);
  5564. DPF_EXIT();
  5565. return FALSE;
  5566. }
  5567. #undef DPF_MODNAME
  5568. #define DPF_MODNAME "SpeakerTestResetHandler"
  5569. BOOL SpeakerTestResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5570. {
  5571. DPF_ENTER();
  5572. DPF_EXIT();
  5573. return FALSE;
  5574. }
  5575. #undef DPF_MODNAME
  5576. #define DPF_MODNAME "SpeakerTestVScrollHandler"
  5577. BOOL SpeakerTestVScrollHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5578. {
  5579. DPF_ENTER();
  5580. HWND hwndSlider;
  5581. DWORD dwSliderPos;
  5582. psinfo->GetHWNDInputVolumeSlider(&hwndSlider);
  5583. if (hwndSlider == (HWND)lParam)
  5584. {
  5585. // the user is moving the input slider
  5586. dwSliderPos = (DWORD)SendMessage(hwndSlider, TBM_GETPOS, 0, 0);
  5587. // set the input volume to the user's request
  5588. psinfo->SetRecordVolume(AmpFactorToDB(DBToAmpFactor(DSBVOLUME_MAX)-dwSliderPos));
  5589. }
  5590. psinfo->GetHWNDOutputVolumeSlider(&hwndSlider);
  5591. if (hwndSlider == (HWND)lParam)
  5592. {
  5593. // the user is moving the output slider
  5594. dwSliderPos = (DWORD) SendMessage(hwndSlider, TBM_GETPOS, 0, 0);
  5595. // set the output volume
  5596. psinfo->SetWaveOutVolume( ((DWORD) SendMessage(hwndSlider, TBM_GETRANGEMAX, 0, 0)) - dwSliderPos);
  5597. }
  5598. DPF_EXIT();
  5599. return FALSE;
  5600. }
  5601. #undef DPF_MODNAME
  5602. #define DPF_MODNAME "SpeakerTestRecAdvancedHandler"
  5603. BOOL SpeakerTestRecAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5604. {
  5605. DPF_ENTER();
  5606. HWND hwndWizard = GetParent(hDlg);
  5607. if (hwndWizard == NULL)
  5608. {
  5609. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed");
  5610. DPF_EXIT();
  5611. return FALSE;
  5612. }
  5613. psinfo->LaunchWindowsVolumeControl(hwndWizard, TRUE);
  5614. DPF_EXIT();
  5615. return FALSE;
  5616. }
  5617. #undef DPF_MODNAME
  5618. #define DPF_MODNAME "SpeakerTestOutAdvancedHandler"
  5619. BOOL SpeakerTestOutAdvancedHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5620. {
  5621. DPF_ENTER();
  5622. HWND hwndWizard = GetParent(hDlg);
  5623. if (hwndWizard == NULL)
  5624. {
  5625. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed");
  5626. DPF_EXIT();
  5627. return FALSE;
  5628. }
  5629. psinfo->LaunchWindowsVolumeControl(hwndWizard, FALSE);
  5630. DPF_EXIT();
  5631. return FALSE;
  5632. }
  5633. #undef DPF_MODNAME
  5634. #define DPF_MODNAME "FullDuplexFailedProc"
  5635. INT_PTR CALLBACK FullDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  5636. {
  5637. DPF_ENTER();
  5638. BOOL fRet;
  5639. LPNMHDR lpnm;
  5640. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  5641. fRet = FALSE;
  5642. switch (message)
  5643. {
  5644. case WM_INITDIALOG :
  5645. fRet = FullDuplexFailedInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  5646. break;
  5647. case WM_NOTIFY :
  5648. lpnm = (LPNMHDR) lParam;
  5649. switch (lpnm->code)
  5650. {
  5651. case PSN_SETACTIVE :
  5652. fRet = FullDuplexFailedSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  5653. break;
  5654. case PSN_WIZFINISH :
  5655. fRet = FullDuplexFailedFinishHandler(hDlg, message, wParam, lParam, psinfo);
  5656. break;
  5657. case PSN_WIZBACK :
  5658. fRet = FullDuplexFailedBackHandler(hDlg, message, wParam, lParam, psinfo);
  5659. break;
  5660. case PSN_RESET :
  5661. fRet = FullDuplexFailedResetHandler(hDlg, message, wParam, lParam, psinfo);
  5662. break;
  5663. default :
  5664. break;
  5665. }
  5666. break;
  5667. default:
  5668. break;
  5669. }
  5670. DPF_EXIT();
  5671. return fRet;
  5672. }
  5673. #undef DPF_MODNAME
  5674. #define DPF_MODNAME "FullDuplexFailedInitDialogHandler"
  5675. BOOL FullDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5676. {
  5677. DPF_ENTER();
  5678. LONG lRet;
  5679. HWND hwndWizard = NULL;
  5680. HWND hwndParent = NULL;
  5681. HWND hwndControl;
  5682. HFONT hfTitle;
  5683. HICON hIcon;
  5684. HRESULT hr = DV_OK;
  5685. // Get the shared data from PROPSHEETPAGE lParam value
  5686. // and load it into GWLP_USERDATA
  5687. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  5688. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  5689. // Get the parent window
  5690. hwndWizard = GetParent(hDlg);
  5691. if (hwndWizard == NULL)
  5692. {
  5693. lRet = GetLastError();
  5694. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5695. hr = DVERR_GENERIC;
  5696. goto error_cleanup;
  5697. }
  5698. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  5699. if (hwndControl == NULL)
  5700. {
  5701. // error, log it and bail
  5702. lRet = GetLastError();
  5703. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5704. hr = DVERR_GENERIC;
  5705. goto error_cleanup;
  5706. }
  5707. psinfo->GetTitleFont(&hfTitle);
  5708. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE);
  5709. // load the warning icon
  5710. hIcon = LoadIcon(NULL, IDI_WARNING);
  5711. SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
  5712. DPF_EXIT();
  5713. return FALSE;
  5714. error_cleanup:
  5715. psinfo->GetHWNDParent(&hwndParent);
  5716. DV_DisplayErrorBox(hr, hwndParent);
  5717. psinfo->SetError(hr);
  5718. psinfo->Abort(hDlg, hr);
  5719. DPF_EXIT();
  5720. return FALSE;
  5721. }
  5722. #undef DPF_MODNAME
  5723. #define DPF_MODNAME "FullDuplexFailedSetActiveHandler"
  5724. BOOL FullDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5725. {
  5726. DPF_ENTER();
  5727. LONG lRet;
  5728. HWND hwndWizard;
  5729. HWND hwndParent = NULL;
  5730. HANDLE hEvent;
  5731. HRESULT hr;
  5732. PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC );
  5733. // Get the parent window
  5734. hwndWizard = GetParent(hDlg);
  5735. if (hwndWizard == NULL)
  5736. {
  5737. lRet = GetLastError();
  5738. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5739. hr = DVERR_GENERIC;
  5740. goto error_cleanup;
  5741. }
  5742. // set the HWNDs
  5743. psinfo->SetHWNDWizard(hwndWizard);
  5744. psinfo->SetHWNDDialog(hDlg);
  5745. psinfo->SetHWNDProgress(NULL);
  5746. psinfo->SetHWNDInputPeak(NULL);
  5747. psinfo->SetHWNDOutputPeak(NULL);
  5748. psinfo->SetHWNDInputVolumeSlider(NULL);
  5749. psinfo->SetHWNDOutputVolumeSlider(NULL);
  5750. PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_FINISH);
  5751. DPF_EXIT();
  5752. return FALSE;
  5753. error_cleanup:
  5754. psinfo->GetHWNDParent(&hwndParent);
  5755. DV_DisplayErrorBox(hr, hwndParent);
  5756. psinfo->SetError(hr);
  5757. psinfo->Abort(hDlg, hr);
  5758. DPF_EXIT();
  5759. return FALSE;
  5760. }
  5761. #undef DPF_MODNAME
  5762. #define DPF_MODNAME "FullDuplexFailedFinishHandler"
  5763. BOOL FullDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5764. {
  5765. DPF_ENTER();
  5766. psinfo->Finish();
  5767. DPF_EXIT();
  5768. return FALSE;
  5769. }
  5770. #undef DPF_MODNAME
  5771. #define DPF_MODNAME "FullDuplexFailedResetHandler"
  5772. BOOL FullDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5773. {
  5774. DPF_ENTER();
  5775. DPF_EXIT();
  5776. return FALSE;
  5777. }
  5778. #undef DPF_MODNAME
  5779. #define DPF_MODNAME "FullDuplexFailedBackHandler"
  5780. BOOL FullDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5781. {
  5782. DPF_ENTER();
  5783. // go back to the full duplex test page
  5784. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST);
  5785. DPF_EXIT();
  5786. return TRUE;
  5787. }
  5788. #undef DPF_MODNAME
  5789. #define DPF_MODNAME "HalfDuplexFailedProc"
  5790. INT_PTR CALLBACK HalfDuplexFailedProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  5791. {
  5792. DPF_ENTER();
  5793. BOOL fRet;
  5794. LPNMHDR lpnm;
  5795. CSupervisorInfo* psinfo = (CSupervisorInfo*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  5796. fRet = FALSE;
  5797. switch (message)
  5798. {
  5799. case WM_INITDIALOG :
  5800. fRet = HalfDuplexFailedInitDialogHandler(hDlg, message, wParam, lParam, psinfo);
  5801. break;
  5802. case WM_NOTIFY :
  5803. lpnm = (LPNMHDR) lParam;
  5804. switch (lpnm->code)
  5805. {
  5806. case PSN_SETACTIVE :
  5807. fRet = HalfDuplexFailedSetActiveHandler(hDlg, message, wParam, lParam, psinfo);
  5808. break;
  5809. case PSN_WIZFINISH :
  5810. fRet = HalfDuplexFailedFinishHandler(hDlg, message, wParam, lParam, psinfo);
  5811. break;
  5812. case PSN_WIZBACK :
  5813. fRet = HalfDuplexFailedBackHandler(hDlg, message, wParam, lParam, psinfo);
  5814. break;
  5815. case PSN_RESET :
  5816. fRet = HalfDuplexFailedResetHandler(hDlg, message, wParam, lParam, psinfo);
  5817. break;
  5818. default :
  5819. break;
  5820. }
  5821. break;
  5822. default:
  5823. break;
  5824. }
  5825. DPF_EXIT();
  5826. return fRet;
  5827. }
  5828. #undef DPF_MODNAME
  5829. #define DPF_MODNAME "HalfDuplexFailedInitDialogHandler"
  5830. BOOL HalfDuplexFailedInitDialogHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5831. {
  5832. DPF_ENTER();
  5833. LONG lRet;
  5834. HWND hwndWizard = NULL;
  5835. HWND hwndParent = NULL;
  5836. HWND hwndControl;
  5837. HFONT hfTitle;
  5838. HICON hIcon;
  5839. HRESULT hr = DV_OK;
  5840. // Get the shared data from PROPSHEETPAGE lParam value
  5841. // and load it into GWLP_USERDATA
  5842. psinfo = (CSupervisorInfo*)((LPPROPSHEETPAGE)lParam)->lParam;
  5843. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)psinfo);
  5844. // Get the parent window
  5845. hwndWizard = GetParent(hDlg);
  5846. if (hwndWizard == NULL)
  5847. {
  5848. lRet = GetLastError();
  5849. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5850. hr = DVERR_GENERIC;
  5851. goto error_cleanup;
  5852. }
  5853. hwndControl = GetDlgItem(hDlg, IDC_TITLE);
  5854. if (hwndControl == NULL)
  5855. {
  5856. // error, log it and bail
  5857. lRet = GetLastError();
  5858. Diagnostics_Write(DVF_ERRORLEVEL, "GetDlgItem failed, code: %i", lRet);
  5859. hr = DVERR_GENERIC;
  5860. goto error_cleanup;
  5861. }
  5862. psinfo->GetTitleFont(&hfTitle);
  5863. (void)::SendMessage(hwndControl, WM_SETFONT, (WPARAM)hfTitle, (LPARAM)TRUE);
  5864. // load the warning icon
  5865. hIcon = LoadIcon(NULL, IDI_WARNING);
  5866. SendDlgItemMessage(hDlg, IDC_WARNINGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
  5867. DPF_EXIT();
  5868. return FALSE;
  5869. error_cleanup:
  5870. psinfo->GetHWNDParent(&hwndParent);
  5871. DV_DisplayErrorBox(hr, hwndParent);
  5872. psinfo->SetError(hr);
  5873. psinfo->Abort(hDlg, hr);
  5874. DPF_EXIT();
  5875. return FALSE;
  5876. }
  5877. #undef DPF_MODNAME
  5878. #define DPF_MODNAME "HalfDuplexFailedSetActiveHandler"
  5879. BOOL HalfDuplexFailedSetActiveHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5880. {
  5881. DPF_ENTER();
  5882. LONG lRet;
  5883. HWND hwndWizard;
  5884. HWND hwndParent = NULL;
  5885. HANDLE hEvent;
  5886. HRESULT hr;
  5887. PlaySound( _T("SystemExclamation"), NULL, SND_ASYNC );
  5888. // Get the parent window
  5889. hwndWizard = GetParent(hDlg);
  5890. if (hwndWizard == NULL)
  5891. {
  5892. lRet = GetLastError();
  5893. Diagnostics_Write(DVF_ERRORLEVEL, "GetParent failed, code: %i", lRet);
  5894. hr = DVERR_GENERIC;
  5895. goto error_cleanup;
  5896. }
  5897. // set the HWNDs
  5898. psinfo->SetHWNDWizard(hwndWizard);
  5899. psinfo->SetHWNDDialog(hDlg);
  5900. psinfo->SetHWNDProgress(NULL);
  5901. psinfo->SetHWNDInputPeak(NULL);
  5902. psinfo->SetHWNDOutputPeak(NULL);
  5903. psinfo->SetHWNDInputVolumeSlider(NULL);
  5904. psinfo->SetHWNDOutputVolumeSlider(NULL);
  5905. PropSheet_SetWizButtons(hwndWizard, PSWIZB_BACK|PSWIZB_FINISH);
  5906. DPF_EXIT();
  5907. return FALSE;
  5908. error_cleanup:
  5909. psinfo->GetHWNDParent(&hwndParent);
  5910. DV_DisplayErrorBox(hr, hwndParent);
  5911. psinfo->SetError(hr);
  5912. psinfo->Abort(hDlg, hr);
  5913. DPF_EXIT();
  5914. return FALSE;
  5915. }
  5916. #undef DPF_MODNAME
  5917. #define DPF_MODNAME "HalfDuplexFailedFinishHandler"
  5918. BOOL HalfDuplexFailedFinishHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5919. {
  5920. DPF_ENTER();
  5921. psinfo->Finish();
  5922. DPF_EXIT();
  5923. return FALSE;
  5924. }
  5925. #undef DPF_MODNAME
  5926. #define DPF_MODNAME "HalfDuplexFailedResetHandler"
  5927. BOOL HalfDuplexFailedResetHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5928. {
  5929. DPF_ENTER();
  5930. DPF_EXIT();
  5931. return FALSE;
  5932. }
  5933. #undef DPF_MODNAME
  5934. #define DPF_MODNAME "HalfDuplexFailedBackHandler"
  5935. BOOL HalfDuplexFailedBackHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, CSupervisorInfo* psinfo)
  5936. {
  5937. DPF_ENTER();
  5938. // go back to the full duplex test page
  5939. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_FULLDUPLEXTEST);
  5940. DPF_EXIT();
  5941. return TRUE;
  5942. }