Source code of Windows XP (NT5)
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.

6914 lines
169 KiB

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