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

514 lines
19 KiB

  1. #include "stdafx.h"
  2. #include "resource.h"
  3. #include <sapi.h>
  4. #include <string.h>
  5. #include "audiodlg.h"
  6. #include <spddkhlp.h>
  7. #include <stdio.h>
  8. /*****************************************************************************
  9. * AudioDlgProc *
  10. *--------------*
  11. * Description:
  12. * DLGPROC for choosing the default audio input/output
  13. ****************************************************************** BECKYW ***/
  14. INT_PTR CALLBACK AudioDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  15. {
  16. static CSpUnicodeSupport unicode;
  17. CAudioDlg *pAudioDlg = (CAudioDlg *) unicode.GetWindowLongPtr( hWnd, GWLP_USERDATA );
  18. SPDBG_FUNC( "AudioDlgProc" );
  19. CComPtr<ISpObjectToken> cpToken;
  20. switch (uMsg)
  21. {
  22. case WM_INITDIALOG:
  23. // pAudioDlg comes in on the lParam
  24. pAudioDlg = (CAudioDlg *) lParam;
  25. // Set pAudioDlg to the window long so we can get it later
  26. unicode.SetWindowLongPtr( hWnd, GWLP_USERDATA, lParam );
  27. pAudioDlg->OnInitDialog(hWnd);
  28. break;
  29. case WM_DESTROY:
  30. pAudioDlg->OnDestroy();
  31. break;
  32. case WM_COMMAND:
  33. if ( LOWORD( wParam ) == IDOK )
  34. {
  35. // Determine if there are changes to commit
  36. WCHAR pwszRequestedDefault[ MAX_PATH ];
  37. pwszRequestedDefault[0] = 0;
  38. if ( pAudioDlg->GetRequestedDefaultTokenID( pwszRequestedDefault, MAX_PATH ) )
  39. {
  40. // What kind of changes have been made?
  41. pAudioDlg->m_fChangesToCommit =
  42. (pAudioDlg->m_dstrCurrentDefaultTokenId &&
  43. (0 != wcsicmp( pwszRequestedDefault, pAudioDlg->m_dstrCurrentDefaultTokenId )));
  44. pAudioDlg->m_fChangesSinceLastTime =
  45. (pAudioDlg->m_dstrCurrentDefaultTokenId &&
  46. (0 != wcsicmp( pwszRequestedDefault, pAudioDlg->m_dstrDefaultTokenIdBeforeOK )));
  47. }
  48. if ( pAudioDlg->m_fChangesSinceLastTime )
  49. {
  50. pAudioDlg->m_dstrLastRequestedDefaultTokenId = pwszRequestedDefault;
  51. }
  52. ::EndDialog( hWnd, true );
  53. }
  54. else if ( LOWORD( wParam ) == IDCANCEL )
  55. {
  56. // There are no changes to commit
  57. pAudioDlg->m_fChangesSinceLastTime = false;
  58. ::EndDialog( hWnd, false );
  59. }
  60. // Handle the volume button
  61. else if ( LOWORD( wParam ) == ID_TTS_VOL )
  62. {
  63. pAudioDlg->GetAudioToken(&cpToken);
  64. CSpDynamicString wszTitle;
  65. CComPtr<ISpObjectWithToken> cpSpObjectWithToken;
  66. HRESULT hr = S_OK;
  67. hr = cpToken->CreateInstance(
  68. NULL, CLSCTX_INPROC_SERVER, IID_ISpObjectWithToken,
  69. (void **)&cpSpObjectWithToken);
  70. if (SUCCEEDED(hr))
  71. {
  72. WCHAR wszTitle[256];
  73. ::LoadString(_Module.GetResourceInstance(), IDS_AUDIO_VOLUME, wszTitle, 256);
  74. hr = cpToken->DisplayUI(pAudioDlg->GetHDlg(), wszTitle, SPDUI_AudioVolume, NULL, 0, cpSpObjectWithToken);
  75. }
  76. SPDBG_REPORT_ON_FAIL(hr);
  77. }
  78. // Handle the audio properties button
  79. else if ( LOWORD(wParam) == IDC_AUDIO_PROPERTIES)
  80. {
  81. pAudioDlg->GetAudioToken(&cpToken);
  82. CSpDynamicString wszTitle;
  83. CComPtr<ISpObjectWithToken> cpSpObjectWithToken;
  84. HRESULT hr = S_OK;
  85. hr = cpToken->CreateInstance(
  86. NULL, CLSCTX_INPROC_SERVER, IID_ISpObjectWithToken,
  87. (void **)&cpSpObjectWithToken);
  88. if (SUCCEEDED(hr))
  89. {
  90. WCHAR wszTitle[256];
  91. ::LoadString(_Module.GetResourceInstance(), IDS_AUDIO_PROPERTIES, wszTitle, 256);
  92. hr = cpToken->DisplayUI(pAudioDlg->GetHDlg(), wszTitle, SPDUI_AudioProperties, NULL, 0, cpSpObjectWithToken);
  93. }
  94. SPDBG_REPORT_ON_FAIL(hr);
  95. }
  96. // Handle a selection change for the audio device
  97. else if (( IDC_DEFAULT_DEVICE == LOWORD( wParam ) ) &&
  98. ( CBN_SELCHANGE == HIWORD( wParam ) ))
  99. {
  100. SPDBG_ASSERT( !pAudioDlg->IsPreferredDevice() );
  101. pAudioDlg->GetAudioToken(&cpToken);
  102. pAudioDlg->UpdateDlgUI(cpToken);
  103. }
  104. // Handle a click to either the preferred or 'this device' radio buttons
  105. else if (HIWORD(wParam) == BN_CLICKED)
  106. {
  107. bool bPreferred;
  108. if( LOWORD(wParam) == IDC_PREFERRED_MM_DEVICE)
  109. {
  110. bPreferred = true;
  111. }
  112. else if(LOWORD(wParam) == IDC_THIS_DEVICE)
  113. {
  114. bPreferred = false;
  115. }
  116. ::EnableWindow( ::GetDlgItem(pAudioDlg->GetHDlg(), IDC_DEFAULT_DEVICE), !bPreferred );
  117. pAudioDlg->SetPreferredDevice( bPreferred );
  118. pAudioDlg->GetAudioToken(&cpToken);
  119. pAudioDlg->UpdateDlgUI(cpToken);
  120. }
  121. break;
  122. }
  123. return FALSE;
  124. } /* AudioDlgProc */
  125. /*****************************************************************************
  126. * CAudioDlg::OnInitDialog *
  127. *-------------------------*
  128. * Description:
  129. * Dialog Initialization
  130. ****************************************************************** BECKYW ***/
  131. void CAudioDlg::OnInitDialog(HWND hWnd)
  132. {
  133. SPDBG_FUNC( "CAudioDlg::OnInitDialog" );
  134. SPDBG_ASSERT(IsWindow(hWnd));
  135. m_hDlg = hWnd;
  136. // Set the appropriate captions
  137. WCHAR wszCaption[ MAX_LOADSTRING ];
  138. HINSTANCE hInst = _Module.GetResourceInstance();
  139. // Main Window Caption
  140. ::LoadString( hInst,
  141. (m_iotype == eINPUT) ? IDS_DEFAULT_SPEECH_INPUT : IDS_DEFAULT_SPEECH_OUTPUT,
  142. wszCaption, MAX_LOADSTRING );
  143. ::SendMessage( hWnd, WM_SETTEXT, 0, (LPARAM) wszCaption );
  144. // Group Box Caption
  145. ::LoadString( hInst,
  146. (m_iotype == eINPUT) ? IDS_DEFAULT_INPUT : IDS_DEFAULT_OUTPUT,
  147. wszCaption, MAX_LOADSTRING );
  148. ::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_AUDIO_GROUPBOX ),
  149. WM_SETTEXT, 0, (LPARAM) wszCaption );
  150. // Preferred Caption
  151. ::LoadString( hInst,
  152. (m_iotype == eINPUT) ? IDS_PREFERRED_INPUT : IDS_PREFERRED_OUTPUT,
  153. wszCaption, MAX_LOADSTRING );
  154. ::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_PREFERRED_MM_DEVICE ),
  155. WM_SETTEXT, 0, (LPARAM) wszCaption );
  156. // Specific Caption
  157. ::LoadString( hInst,
  158. (m_iotype == eINPUT) ? IDS_SPECIFIC_INPUT : IDS_SPECIFIC_OUTPUT,
  159. wszCaption, MAX_LOADSTRING );
  160. ::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_THIS_DEVICE ),
  161. WM_SETTEXT, 0, (LPARAM) wszCaption );
  162. // MSAA Specific Caption
  163. ::LoadString( hInst,
  164. (m_iotype == eINPUT) ? IDS_SPECIFIC_INPUT2 : IDS_SPECIFIC_OUTPUT2,
  165. wszCaption, MAX_LOADSTRING );
  166. ::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_THIS_DEVICE2 ),
  167. WM_SETTEXT, 0, (LPARAM) wszCaption );
  168. // Volume Button
  169. ::LoadString( hInst,
  170. IDS_VOLUME,
  171. wszCaption, MAX_LOADSTRING );
  172. ::SendMessage( (HWND) ::GetDlgItem( hWnd, ID_TTS_VOL ),
  173. WM_SETTEXT, 0, (LPARAM) wszCaption );
  174. // Properties Button
  175. ::LoadString( hInst,
  176. IDS_PROPERTIES,
  177. wszCaption, MAX_LOADSTRING );
  178. ::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_AUDIO_PROPERTIES ),
  179. WM_SETTEXT, 0, (LPARAM) wszCaption );
  180. const WCHAR *pszCategory = (m_iotype == eINPUT) ? SPCAT_AUDIOIN : SPCAT_AUDIOOUT;
  181. const WCHAR *pszMMSysEnum = (m_iotype == eINPUT)
  182. ? SPMMSYS_AUDIO_IN_TOKEN_ID
  183. : SPMMSYS_AUDIO_OUT_TOKEN_ID;
  184. HRESULT hr = S_OK;
  185. if ( !m_dstrCurrentDefaultTokenId )
  186. {
  187. hr = SpGetDefaultTokenIdFromCategoryId( pszCategory, &m_dstrCurrentDefaultTokenId );
  188. }
  189. if (SUCCEEDED(hr))
  190. {
  191. // Determine what the initial setting will appear as
  192. if ( m_dstrLastRequestedDefaultTokenId )
  193. {
  194. // An audio change was previously OK'ed
  195. m_dstrDefaultTokenIdBeforeOK = m_dstrLastRequestedDefaultTokenId;
  196. // The current default could be different if the user OK'ed a change
  197. // but did not apply it
  198. m_fChangesToCommit = ( 0 != wcsicmp( m_dstrCurrentDefaultTokenId,
  199. m_dstrDefaultTokenIdBeforeOK ) );
  200. }
  201. else
  202. {
  203. // No audio change was previously OK'ed
  204. if ( !m_dstrDefaultTokenIdBeforeOK )
  205. {
  206. m_dstrDefaultTokenIdBeforeOK = m_dstrCurrentDefaultTokenId;
  207. }
  208. }
  209. if (wcsicmp(m_dstrDefaultTokenIdBeforeOK, pszMMSysEnum) == 0)
  210. {
  211. // This message will cause the check button to be correct.
  212. ::SendMessage( ::GetDlgItem(m_hDlg, IDC_PREFERRED_MM_DEVICE), BM_SETCHECK, true, 0L );
  213. // This message will cause the volume button to be enabled or disabled as appropriate
  214. ::SendMessage( m_hDlg, WM_COMMAND, MAKELONG( IDC_PREFERRED_MM_DEVICE, BN_CLICKED ),
  215. (LPARAM) ::GetDlgItem( m_hDlg, IDC_PREFERRED_MM_DEVICE ) );
  216. }
  217. else
  218. {
  219. // This message will cause the check button to be correct.
  220. ::SendMessage( ::GetDlgItem(m_hDlg, IDC_THIS_DEVICE), BM_SETCHECK, true, 0L );
  221. }
  222. // Initialize the list of audio devices
  223. hr = SpInitTokenComboBox( ::GetDlgItem( hWnd, IDC_DEFAULT_DEVICE ),
  224. (m_iotype == eINPUT) ? SPCAT_AUDIOIN : SPCAT_AUDIOOUT );
  225. }
  226. if (S_OK == hr)
  227. {
  228. if ( BST_CHECKED == ::SendMessage( ::GetDlgItem( m_hDlg, IDC_THIS_DEVICE ), BM_GETCHECK, 0, 0 ) )
  229. {
  230. // Select the appropriate default token ID here by going through the
  231. // stuff in the list and selecting the one whose token ID matches
  232. // m_dstrDefaultTokenIdBeforeOK
  233. int nTokens = (int)::SendDlgItemMessage( m_hDlg, IDC_DEFAULT_DEVICE, CB_GETCOUNT, 0, 0 );
  234. int iItem = 0;
  235. CSpDynamicString dstrTokenId;
  236. bool fFound = false;
  237. for ( iItem = 0;
  238. (iItem < nTokens) && !fFound;
  239. iItem++ )
  240. {
  241. ISpObjectToken *pToken = (ISpObjectToken *) ::SendDlgItemMessage( m_hDlg,
  242. IDC_DEFAULT_DEVICE, CB_GETITEMDATA, iItem, 0 );
  243. HRESULT hr = E_FAIL;
  244. if ( pToken )
  245. {
  246. hr = pToken->GetId(&dstrTokenId);
  247. }
  248. if ( SUCCEEDED( hr ) )
  249. {
  250. fFound = (0 == wcsicmp( m_dstrDefaultTokenIdBeforeOK, dstrTokenId ));
  251. }
  252. dstrTokenId = (WCHAR *) NULL;
  253. }
  254. SPDBG_ASSERT( fFound );
  255. ::SendDlgItemMessage( m_hDlg, IDC_DEFAULT_DEVICE, CB_SETCURSEL, iItem - 1, 0 );
  256. // This message will cause the volume button to be enabled or disabled as appropriate
  257. ::SendMessage( m_hDlg, WM_COMMAND, MAKELONG( IDC_THIS_DEVICE, BN_CLICKED ),
  258. (LPARAM) ::GetDlgItem( m_hDlg, IDC_THIS_DEVICE ) );
  259. }
  260. ::SetCursor( ::LoadCursor( NULL, IDC_ARROW ) );
  261. }
  262. else
  263. {
  264. WCHAR szError[ MAX_LOADSTRING ];
  265. WCHAR szIO[ MAX_LOADSTRING ];
  266. WCHAR szErrorTemplate[ MAX_LOADSTRING ];
  267. ::LoadString( _Module.GetResourceInstance(), IDS_NO_DEVICES, szErrorTemplate, sp_countof( szErrorTemplate ) );
  268. ::LoadString( _Module.GetResourceInstance(), (eINPUT == m_iotype) ? IDS_INPUT : IDS_OUTPUT, szIO, sp_countof( szIO ) );
  269. swprintf( szError, szErrorTemplate, szIO );
  270. ::MessageBox( m_hDlg, szError, NULL, MB_ICONEXCLAMATION | g_dwIsRTLLayout );
  271. if ( FAILED( hr ) )
  272. {
  273. ::EndDialog( m_hDlg, -1 );
  274. }
  275. else
  276. {
  277. ::EnableWindow( ::GetDlgItem( m_hDlg, IDC_THIS_DEVICE ), FALSE );
  278. ::EnableWindow( ::GetDlgItem( m_hDlg, IDC_DEFAULT_DEVICE ), FALSE );
  279. ::EnableWindow( ::GetDlgItem( m_hDlg, IDC_PREFERRED_MM_DEVICE ), FALSE );
  280. ::EnableWindow( ::GetDlgItem( m_hDlg, IDC_AUDIO_PROPERTIES ), FALSE );
  281. ::EnableWindow( ::GetDlgItem( m_hDlg, ID_TTS_VOL ), FALSE );
  282. }
  283. }
  284. } /* CAudioDlg::OnInitDialog */
  285. /*****************************************************************************
  286. * CAudioDlg::OnDestroy *
  287. *----------------------*
  288. * Description:
  289. * Destruction
  290. ****************************************************************** BECKYW ***/
  291. void CAudioDlg::OnDestroy()
  292. {
  293. SPDBG_FUNC( "CAudioDlg::OnDestroy" );
  294. SpDestroyTokenComboBox( ::GetDlgItem( m_hDlg, IDC_DEFAULT_DEVICE ) );
  295. } /* CAudioDlg::OnDestroy */
  296. /*****************************************************************************
  297. * CAudioDlg::OnApply *
  298. *--------------------*
  299. * Description:
  300. * Set user specified options
  301. ****************************************************************** BECKYW ***/
  302. HRESULT CAudioDlg::OnApply()
  303. {
  304. SPDBG_FUNC( "CAudioDlg::OnApply" );
  305. if ( !m_dstrLastRequestedDefaultTokenId )
  306. {
  307. // nothing to apply
  308. return S_FALSE;
  309. }
  310. HRESULT hr;
  311. CComPtr<ISpObjectTokenCategory> cpCategory;
  312. hr = SpGetCategoryFromId(
  313. m_iotype == eINPUT
  314. ? SPCAT_AUDIOIN
  315. : SPCAT_AUDIOOUT,
  316. &cpCategory);
  317. if ( SUCCEEDED( hr ) )
  318. {
  319. hr = cpCategory->SetDefaultTokenId( m_dstrLastRequestedDefaultTokenId );
  320. }
  321. // Next time we bring this up we should show the actual default
  322. m_dstrLastRequestedDefaultTokenId = (WCHAR *) NULL;
  323. m_dstrDefaultTokenIdBeforeOK = (WCHAR *) NULL;
  324. return hr;
  325. } /* CAudioDlg::OnApply */
  326. /*****************************************************************************
  327. * CAudioDlg::GetRequestedDefaultTokenID *
  328. *---------------------------------------*
  329. * Description:
  330. * Looks at the UI and gets the token ID that the user wants to switch
  331. * to. This is returned in pwszNewID.
  332. * Return:
  333. * Number of characters in the ID
  334. ****************************************************************** BECKYW ***/
  335. UINT CAudioDlg::GetRequestedDefaultTokenID( WCHAR *pwszNewID, UINT cLength )
  336. {
  337. if ( !pwszNewID )
  338. {
  339. return 0;
  340. }
  341. CComPtr<ISpObjectTokenCategory> cpCategory;
  342. HRESULT hr = SpGetCategoryFromId(
  343. m_iotype == eINPUT
  344. ? SPCAT_AUDIOIN
  345. : SPCAT_AUDIOOUT,
  346. &cpCategory);
  347. if (SUCCEEDED(hr))
  348. {
  349. if( ::SendMessage( ::GetDlgItem(m_hDlg, IDC_PREFERRED_MM_DEVICE), BM_GETCHECK, 0, 0L ) == BST_CHECKED )
  350. {
  351. const WCHAR *pwszMMSysAudioID = (m_iotype == eINPUT) ?
  352. SPMMSYS_AUDIO_IN_TOKEN_ID :
  353. SPMMSYS_AUDIO_OUT_TOKEN_ID;
  354. UINT cMMSysAudioIDLength = wcslen( pwszMMSysAudioID );
  355. UINT cRet = __min( cLength - 1, cMMSysAudioIDLength );
  356. wcsncpy( pwszNewID, pwszMMSysAudioID, cRet );
  357. pwszNewID[ cRet ] = 0;
  358. return cRet;
  359. }
  360. else
  361. {
  362. ISpObjectToken *pToken = SpGetCurSelComboBoxToken( ::GetDlgItem( m_hDlg, IDC_DEFAULT_DEVICE ) );
  363. if (pToken)
  364. {
  365. CSpDynamicString dstrTokenId;
  366. hr = pToken->GetId(&dstrTokenId);
  367. if (SUCCEEDED(hr))
  368. {
  369. UINT cIDLength = wcslen( dstrTokenId );
  370. UINT cRet = __min( cLength - 1, cIDLength );
  371. wcsncpy( pwszNewID, dstrTokenId, cRet );
  372. pwszNewID[ cRet ] = 0;
  373. return cRet;
  374. }
  375. }
  376. }
  377. }
  378. // There was an error
  379. return 0;
  380. } /* CAudioDlg::GetRequestedDefaultTokenID */
  381. /*****************************************************************************
  382. * CAudioDlg::GetAudioToken *
  383. *--------------------------*
  384. * Description:
  385. * Returns an interface to the currently selected token. Currently this
  386. * can either be the 'preferred' device in which case, the object is created
  387. * on the fly. Or it can be one from the drop-down list which contains an
  388. * attached token. In this case, it needs to be addref'd so that the returned
  389. * token is consistent regardless of the source inside this function.
  390. *
  391. * NB: This requires the caller to call release on the instance.
  392. *
  393. * Return:
  394. **************************************************************** AGARSIDE ***/
  395. HRESULT CAudioDlg::GetAudioToken(ISpObjectToken **ppToken)
  396. {
  397. HRESULT hr = S_OK;
  398. *ppToken = NULL;
  399. if (IsPreferredDevice())
  400. {
  401. hr = SpGetTokenFromId((this->IsInput())?(SPMMSYS_AUDIO_IN_TOKEN_ID):(SPMMSYS_AUDIO_OUT_TOKEN_ID),
  402. ppToken,
  403. FALSE);
  404. SPDBG_ASSERT(SUCCEEDED(hr));
  405. }
  406. else
  407. {
  408. *ppToken = SpGetCurSelComboBoxToken( GetDlgItem(this->GetHDlg(), IDC_DEFAULT_DEVICE) );
  409. (*ppToken)->AddRef();
  410. }
  411. return S_OK;
  412. }
  413. /*****************************************************************************
  414. * CAudioDlg::UpdateDlgUI *
  415. *------------------------*
  416. * Description:
  417. * Return:
  418. **************************************************************** AGARSIDE ***/
  419. HRESULT CAudioDlg::UpdateDlgUI(ISpObjectToken *pToken)
  420. {
  421. SPDBG_FUNC("CAudioDlg::UpdateDlgUI");
  422. HRESULT hr = S_OK;
  423. BOOL fSupported;
  424. CComPtr<ISpObjectWithToken> cpSpObjectWithToken;
  425. // Get hold of ISpObjectWithToken
  426. hr = pToken->CreateInstance(
  427. NULL, CLSCTX_INPROC_SERVER, IID_ISpObjectWithToken,
  428. (void **)&cpSpObjectWithToken);
  429. // Update volume button status.
  430. fSupported = FALSE;
  431. if (SUCCEEDED(hr))
  432. {
  433. pToken->IsUISupported(SPDUI_AudioVolume, NULL, 0, cpSpObjectWithToken, &fSupported);
  434. ::EnableWindow( ::GetDlgItem(this->GetHDlg(), ID_TTS_VOL), fSupported);
  435. }
  436. // Update UI button status.
  437. fSupported = FALSE;
  438. if (SUCCEEDED(hr))
  439. {
  440. pToken->IsUISupported(SPDUI_AudioProperties, NULL, 0, cpSpObjectWithToken, &fSupported);
  441. ::EnableWindow( ::GetDlgItem(this->GetHDlg(), IDC_AUDIO_PROPERTIES), fSupported);
  442. }
  443. SPDBG_REPORT_ON_FAIL(hr);
  444. return hr;
  445. }