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.

596 lines
15 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dvretro.c
  6. * Content: Retrofit functions
  7. * History:
  8. *
  9. * Date By Reason
  10. * ==== == ======
  11. * 08/12/99 rodtoll created it
  12. * 08/19/99 rodtoll Updated lobby launching to support retrofit
  13. * 08/20/99 rodtoll Modified to respond to shutdown request and
  14. * do proper lobby launch when in client mode.
  15. * 08/25/99 rodtoll Updated to use new GUID based compression selection
  16. * 09/14/99 rodtoll Updated for new Init call and SoundDeviceInfo usage.
  17. * 09/27(8)/99 rodtoll Updated with new interface
  18. * 09/28/99 rodtoll Updated for structure changes.
  19. * 09/29/99 rodtoll Updated for async enum, fixed bug with lobby launch
  20. * 10/15/99 rodtoll Massive code cleanup. Split into multiple files
  21. * rodtoll Minor fix, event was being released twice
  22. * 10/20/99 rodtoll Fixed name info for helper app
  23. * 11/02/99 rodtoll Bug #116677 - Can't use lobby clients that don't hang around
  24. * 11/04/99 pnewson Bug #115297 - launch device test if required
  25. * 11/12/99 rodtoll Added support for the new waveIN/waveOut flags and the
  26. * echo suppression flag. (Can specify them on command-line)
  27. * 12/01/99 rodtoll Bug #115783 - Regardless of device specified always adjusts volume
  28. * for default. Modified dpvhelp to allow user to select play/record
  29. * devices by using /SS switch.
  30. * 12/07/99 rodtoll Bug #122628 Make error messages silent when running in silent mode
  31. * rodtoll Bug #122979 Make invisible to end user
  32. * Now app must be run with /A to show an interface.
  33. * Also, unless /A or /L or /W are specified, the app will exit immediately.
  34. * Command-line help removed.
  35. * Auto-registration code removed for public version of app.
  36. * 02/15/2000 rodtoll Bug #132715 Voice is not working after rejoining the session
  37. * 03/03/2000 rodtoll Updated to handle alternative gamevoice build.
  38. * 06/28/2000 rodtoll Prefix Bug #38033
  39. *
  40. ***************************************************************************/
  41. #include "dxvhelppch.h"
  42. #define MAX_LOADSTRING 100
  43. #define DPVHELP_WINDOWTITLE _T("DirectPlay Voice Chat")
  44. #define DPVHELP_WINDOWCLASS _T("DPVHELP")
  45. #define DPVHELP_PRIVATE_APPNAME _T("DirectPlay Voice Chat (Retrofit)")
  46. #define DPVHELP_PRIVATE_DESC _T("DirectPlay Voice Chat (Retrofit)")
  47. #define DPVHELP_PRIVATE_EXENAME _T("dpvhelp.exe")
  48. #define DPVHELP_PRIVATE_COMMANDLINE _T("/L /S /SC03")
  49. #define DPVHELP_PRIVATE_FLAGS 0x80000002
  50. #undef DPF_MODNAME
  51. #define DPF_MODNAME "InitializeRunTime"
  52. void InitializeRunTime( PDXVHELP_RTINFO prtInfo )
  53. {
  54. prtInfo->hReceiveEvent = NULL;
  55. prtInfo->hThreadDone = CreateEvent( NULL, TRUE, FALSE, NULL );
  56. prtInfo->hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL );
  57. prtInfo->hGo = CreateEvent( NULL, FALSE, FALSE, NULL );
  58. prtInfo->hMainDialog = NULL;
  59. prtInfo->dpidLocalPlayer = 0xFFFFFFFF;
  60. prtInfo->lVolumeHeight = 0;
  61. prtInfo->hInst = NULL;
  62. prtInfo->hMainWnd = NULL;
  63. prtInfo->dwNumClients = 0;
  64. prtInfo->lpdpLobby = NULL;
  65. prtInfo->lpdvClient = NULL;
  66. prtInfo->lpdvServer = NULL;
  67. prtInfo->lpdpDirectPlay = NULL;
  68. prtInfo->hLobbyEvent = NULL;
  69. }
  70. #undef DPF_MODNAME
  71. #define DPF_MODNAME "FreeRunTime"
  72. void FreeRunTime( PDXVHELP_RTINFO prtInfo )
  73. {
  74. CloseHandle( prtInfo->hThreadDone );
  75. CloseHandle( prtInfo->hShutdown );
  76. CloseHandle( prtInfo->hGo );
  77. }
  78. #undef DPF_MODNAME
  79. #define DPF_MODNAME "SetDefaultParameters"
  80. void SetDefaultParameters( PDXVHELP_PARAMETERS pParameters )
  81. {
  82. pParameters->fHost = FALSE;
  83. pParameters->fLobbyLaunched = FALSE;
  84. pParameters->fSilent = TRUE;
  85. pParameters->dwSessionType = DVSESSIONTYPE_PEER;
  86. pParameters->guidCT = DPVCTGUID_DEFAULT;
  87. pParameters->lpszConnectAddress[0] = 0;
  88. pParameters->fAGC = TRUE;
  89. pParameters->fAdvancedUI = FALSE;
  90. pParameters->fWaitForSettings = FALSE;
  91. pParameters->lRecordVolume = DSBVOLUME_MAX;
  92. pParameters->fRegister = FALSE;
  93. pParameters->fUnRegister = FALSE;
  94. pParameters->fKill = FALSE;
  95. pParameters->fIgnoreLobbyDestroy = FALSE;
  96. pParameters->fAllowWaveOut = FALSE;
  97. pParameters->fForceWaveOut = FALSE;
  98. pParameters->fAllowWaveIn = FALSE;
  99. pParameters->fForceWaveIn = FALSE;
  100. pParameters->fEchoSuppression = FALSE;
  101. pParameters->fAutoSelectMic = TRUE;
  102. pParameters->guidPlaybackDevice = DSDEVID_DefaultVoicePlayback;
  103. pParameters->guidRecordDevice = DSDEVID_DefaultVoiceCapture;
  104. pParameters->fSelectCards = FALSE;
  105. pParameters->fStrictFocus = FALSE;
  106. pParameters->fDisableFocus = FALSE;
  107. }
  108. #undef DPF_MODNAME
  109. #define DPF_MODNAME "ProcessCommandLine"
  110. BOOL ProcessCommandLine( PSTR pstrCommandLine, PDXVHELP_PARAMETERS pParameters )
  111. {
  112. PSTR pNextToken = NULL;
  113. pNextToken = _tcstok( pstrCommandLine, _T(" ") );
  114. while( pNextToken != NULL )
  115. {
  116. if( _tcsicmp( pNextToken, _T("/A") ) == 0 )
  117. {
  118. pParameters->fAdvancedUI = TRUE;
  119. pParameters->fSilent = FALSE;
  120. }
  121. else if( _tcsicmp( pNextToken, _T("/ES" ) ) == 0 )
  122. {
  123. pParameters->fEchoSuppression = TRUE;
  124. }
  125. else if( _tcsicmp( pNextToken, _T("/WOF") ) == 0 )
  126. {
  127. pParameters->fForceWaveOut = TRUE;
  128. }
  129. else if( _tcsicmp( pNextToken, _T("/NAS") ) == 0 )
  130. {
  131. pParameters->fAutoSelectMic = FALSE;
  132. }
  133. else if( _tcsicmp( pNextToken, _T("/WOA") ) == 0 )
  134. {
  135. pParameters->fAllowWaveOut = TRUE;
  136. }
  137. else if( _tcsicmp( pNextToken, _T("/WIF") ) == 0 )
  138. {
  139. pParameters->fForceWaveIn = TRUE;
  140. }
  141. else if( _tcsicmp( pNextToken, _T("/WIA") ) == 0 )
  142. {
  143. pParameters->fAllowWaveIn = TRUE;
  144. }
  145. else if( _tcsicmp( pNextToken, _T("/ES") ) == 0 )
  146. {
  147. pParameters->fEchoSuppression = TRUE;
  148. }
  149. else if( _tcsicmp( pNextToken, _T("/W") ) == 0 )
  150. {
  151. pParameters->fLobbyLaunched = TRUE;
  152. pParameters->fWaitForSettings = TRUE;
  153. }
  154. else if( _tcsicmp( pNextToken, _T("/L") ) == 0 )
  155. {
  156. pParameters->fLobbyLaunched = TRUE;
  157. pParameters->fWaitForSettings = FALSE;
  158. }
  159. else if( _tcsicmp( pNextToken, _T("/R") ) == 0 )
  160. {
  161. pParameters->fRegister = TRUE;
  162. return FALSE;
  163. }
  164. else if( _tcsicmp( pNextToken, _T("/U") ) == 0 )
  165. {
  166. pParameters->fUnRegister = TRUE;
  167. return FALSE;
  168. }
  169. else if( _tcsicmp( pNextToken, _T("/S") ) == 0 )
  170. {
  171. pParameters->fSilent = TRUE;
  172. }
  173. else if( _tcsicmp( pNextToken, _T("/K") ) == 0 )
  174. {
  175. pParameters->fKill = TRUE;
  176. return FALSE;
  177. }
  178. else if( _tcsicmp( pNextToken, _T("/I") ) == 0 )
  179. {
  180. pParameters->fIgnoreLobbyDestroy = TRUE;
  181. }
  182. else if( _tcsicmp( pNextToken, _T("/GSM") ) == 0 )
  183. {
  184. pParameters->guidCT = DPVCTGUID_GSM;
  185. }
  186. else if( _tcsicmp( pNextToken, _T("/SC03" ) ) == 0 )
  187. {
  188. pParameters->guidCT = DPVCTGUID_SC03;
  189. }
  190. else if( _tcsicmp( pNextToken, _T("/SC06" ) ) == 0 )
  191. {
  192. pParameters->guidCT = DPVCTGUID_SC06;
  193. }
  194. else if( _tcsicmp( pNextToken, _T("/VR12" ) ) == 0 )
  195. {
  196. pParameters->guidCT = DPVCTGUID_VR12;
  197. }
  198. else if( _tcsicmp( pNextToken, _T("/ADPCM" ) ) == 0 )
  199. {
  200. pParameters->guidCT = DPVCTGUID_ADPCM;
  201. }
  202. else if( _tcsicmp( pNextToken, _T("/NONE" ) ) == 0 )
  203. {
  204. pParameters->guidCT = DPVCTGUID_NONE;
  205. }
  206. else if( _tcsicmp( pNextToken, _T("/TRUE" ) ) == 0 )
  207. {
  208. pParameters->guidCT = DPVCTGUID_TRUESPEECH;
  209. }
  210. else if( _tcsicmp( pNextToken, _T("/SS") ) == 0 )
  211. {
  212. pParameters->fSelectCards = TRUE;
  213. }
  214. else if( _tcsicmp( pNextToken, _T("/FS") ) == 0 )
  215. {
  216. pParameters->fStrictFocus = TRUE;
  217. }
  218. else if( _tcsicmp( pNextToken, _T( "/FD" ) ) == 0 )
  219. {
  220. pParameters->fDisableFocus = TRUE;
  221. }
  222. else
  223. {
  224. return FALSE;
  225. }
  226. pNextToken = _tcstok( NULL, _T(" ") );
  227. }
  228. if( !pParameters->fAdvancedUI && !pParameters->fLobbyLaunched )
  229. {
  230. DPFX(DPFPREP, DVF_ERRORLEVEL, "Can only run in test mode and lobby mode" );
  231. return FALSE;
  232. }
  233. return TRUE;
  234. }
  235. #undef DPF_MODNAME
  236. #define DPF_MODNAME "RegisterApplication"
  237. void RegisterApplication()
  238. {
  239. HRESULT hr;
  240. BOOL fFailed = FALSE;
  241. hr = DPVDX_DP_RegisterApplication( DPVHELP_PRIVATE_APPNAME, DPVHELP_PRIVATE_APPID, DPVHELP_PRIVATE_EXENAME,
  242. DPVHELP_PRIVATE_COMMANDLINE, DPVHELP_PRIVATE_DESC, DPVHELP_PRIVATE_FLAGS );
  243. if( FAILED( hr ) )
  244. {
  245. DPVDX_DPERRDisplay( hr, _T("Unable to register private application"), FALSE );
  246. MessageBox( NULL, _T("Registered Application"), DPVHELP_WINDOWTITLE, MB_OK );
  247. }
  248. if( !fFailed )
  249. {
  250. MessageBox( NULL, _T("Registered Application"), DPVHELP_WINDOWTITLE, MB_OK );
  251. }
  252. }
  253. #undef DPF_MODNAME
  254. #define DPF_MODNAME "UnRegisterApplication"
  255. void UnRegisterApplication()
  256. {
  257. HRESULT hr;
  258. BOOL fFailed = FALSE;
  259. hr = DPVDX_DP_UnRegisterApplication( DPVHELP_PRIVATE_APPID );
  260. if( FAILED( hr ) )
  261. {
  262. DPVDX_DPERRDisplay( hr, _T("Unable to un-register private application"), FALSE );
  263. fFailed = TRUE;
  264. }
  265. if( !fFailed )
  266. {
  267. MessageBox( NULL, _T("Un-Registered Application"), DPVHELP_WINDOWTITLE, MB_OK );
  268. }
  269. }
  270. //
  271. // FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
  272. //
  273. // PURPOSE: Processes messages for the main window.
  274. //
  275. // WM_COMMAND - process the application menu
  276. // WM_PAINT - Paint the main window
  277. // WM_DESTROY - post a quit message and return
  278. //
  279. //
  280. #undef DPF_MODNAME
  281. #define DPF_MODNAME "MainWindowProc"
  282. LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  283. {
  284. int wmId, wmEvent;
  285. PAINTSTRUCT ps;
  286. HDC hdc;
  287. TCHAR szHello[MAX_LOADSTRING];
  288. switch (message)
  289. {
  290. case WM_SHOWWINDOW:
  291. break;
  292. case WM_COMMAND:
  293. wmId = LOWORD(wParam);
  294. wmEvent = HIWORD(wParam);
  295. // Parse the menu selections:
  296. switch (wmId)
  297. {
  298. case IDM_EXIT:
  299. DestroyWindow(hWnd);
  300. break;
  301. default:
  302. return DefWindowProc(hWnd, message, wParam, lParam);
  303. }
  304. break;
  305. case WM_PAINT:
  306. hdc = BeginPaint(hWnd, &ps);
  307. EndPaint(hWnd, &ps);
  308. break;
  309. case WM_DESTROY:
  310. PostQuitMessage(0);
  311. break;
  312. default:
  313. return DefWindowProc(hWnd, message, wParam, lParam);
  314. }
  315. return 0;
  316. }
  317. //
  318. // FUNCTION: MyRegisterClass()
  319. //
  320. // PURPOSE: Registers the window class.
  321. //
  322. // COMMENTS:
  323. //
  324. // This function and its usage is only necessary if you want this code
  325. // to be compatible with Win32 systems prior to the 'RegisterClassEx'
  326. // function that was added to Windows 95. It is important to call this function
  327. // so that the application will get 'well formed' small icons associated
  328. // with it.
  329. //
  330. #undef DPF_MODNAME
  331. #define DPF_MODNAME "MyRegisterClass"
  332. ATOM MyRegisterClass(HINSTANCE hInstance)
  333. {
  334. WNDCLASSEX wcex;
  335. wcex.cbSize = sizeof(WNDCLASSEX);
  336. wcex.style = 0; // CS_HREDRAW | CS_VREDRAW;
  337. wcex.lpfnWndProc = (WNDPROC)MainWindowProc;
  338. wcex.cbClsExtra = 0;
  339. wcex.cbWndExtra = 0;
  340. wcex.hInstance = hInstance;
  341. wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX);
  342. wcex.hCursor = NULL; // LoadCursor(NULL, IDC_ARROW);
  343. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  344. wcex.lpszMenuName = NULL; //(LPCSTR)IDC_TESTWIN;
  345. wcex.lpszClassName = DPVHELP_WINDOWCLASS;
  346. wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_DIRECTX);
  347. return RegisterClassEx(&wcex);
  348. }
  349. //
  350. // FUNCTION: InitInstance(HANDLE, int)
  351. //
  352. // PURPOSE: Saves instance handle and creates main window
  353. //
  354. // COMMENTS:
  355. //
  356. // In this function, we save the instance handle in a global variable and
  357. // create and display the main program window.
  358. //
  359. #undef DPF_MODNAME
  360. #define DPF_MODNAME "CreateHiddenMainWindow"
  361. HWND CreateHiddenMainWindow(HINSTANCE hInstance, int nCmdShow )
  362. {
  363. HRESULT hr;
  364. HWND hWnd;
  365. hWnd = CreateWindow(DPVHELP_WINDOWCLASS, DPVHELP_WINDOWTITLE, WS_OVERLAPPEDWINDOW,
  366. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  367. if (!hWnd)
  368. {
  369. hr = GetLastError();
  370. return NULL;
  371. }
  372. ShowWindow(hWnd, SW_HIDE);
  373. UpdateWindow(hWnd);
  374. return hWnd;
  375. }
  376. #undef DPF_MODNAME
  377. #define DPF_MODNAME "CheckFullDuplex"
  378. BOOL CheckFullDuplex( PDXVHELP_PARAMETERS pParameters )
  379. {
  380. PDIRECTPLAYVOICETEST lpdvSetup;
  381. HRESULT hr;
  382. hr = CoCreateInstance( DPVOICE_CLSID_DPVOICE, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceTest, (void **) &lpdvSetup );
  383. if( FAILED( hr ) )
  384. {
  385. DPVDX_DVERRDisplay( hr, _T("Create of setup interface failed"), pParameters->fSilent );
  386. return FALSE;
  387. }
  388. hr = lpdvSetup->CheckAudioSetup( &pParameters->guidPlaybackDevice, &pParameters->guidRecordDevice, NULL, DVFLAGS_QUERYONLY );
  389. if( FAILED( hr ) )
  390. {
  391. if( pParameters->fSilent )
  392. {
  393. lpdvSetup->Release();
  394. return FALSE;
  395. }
  396. hr = lpdvSetup->CheckAudioSetup( &pParameters->guidPlaybackDevice, &pParameters->guidRecordDevice, NULL, 0 );
  397. lpdvSetup->Release();
  398. if( FAILED( hr ) )
  399. {
  400. return FALSE;
  401. }
  402. }
  403. else
  404. {
  405. lpdvSetup->Release();
  406. }
  407. return TRUE;
  408. }
  409. #undef DPF_MODNAME
  410. #define DPF_MODNAME "WinMain"
  411. int APIENTRY WinMain(HINSTANCE hInstance,
  412. HINSTANCE hPrevInstance,
  413. LPSTR lpCmdLine,
  414. int nCmdShow)
  415. {
  416. DWORD dwThreadID;
  417. DXVHELP_RTINFO rtInfo;
  418. BOOL bGotMsg = FALSE;
  419. MSG msg;
  420. HRESULT hr;
  421. INITCOMMONCONTROLSEX InitCC = {0};
  422. BOOL bOK = FALSE;
  423. BOOL fRunTimeInit = FALSE;
  424. // Initialize COM
  425. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  426. if( FAILED( hr ) )
  427. {
  428. return FALSE;
  429. }
  430. if( !DNOSIndirectionInit() )
  431. {
  432. CoUninitialize();
  433. return FALSE;
  434. }
  435. // Setup default parameters
  436. SetDefaultParameters( &rtInfo.dxvParameters );
  437. // Process the command-line
  438. //
  439. // If this function returns false, we are to exit
  440. if( !ProcessCommandLine( lpCmdLine, &rtInfo.dxvParameters ) )
  441. {
  442. if( rtInfo.dxvParameters.fRegister )
  443. {
  444. RegisterApplication();
  445. }
  446. else if( rtInfo.dxvParameters.fUnRegister )
  447. {
  448. UnRegisterApplication();
  449. }
  450. goto EXIT;
  451. }
  452. // Load common-controls
  453. InitCC.dwSize = sizeof InitCC;
  454. bOK = InitCommonControlsEx(&InitCC);
  455. // Register Window Class
  456. MyRegisterClass(hInstance);
  457. // Initialize Events
  458. InitializeRunTime( &rtInfo );
  459. fRunTimeInit = TRUE;
  460. if( rtInfo.dxvParameters.fLobbyLaunched )
  461. {
  462. SetEvent( rtInfo.hGo );
  463. }
  464. // Perform application initialization:
  465. rtInfo.hMainWnd = CreateHiddenMainWindow(hInstance, nCmdShow);
  466. if( rtInfo.hMainWnd == NULL )
  467. {
  468. goto EXIT;
  469. }
  470. rtInfo.hInst = hInstance;
  471. // If user wants to select the soundcard
  472. if( rtInfo.dxvParameters.fSelectCards )
  473. {
  474. GetCardSettings( rtInfo.hInst, NULL, &rtInfo.dxvParameters.guidPlaybackDevice, &rtInfo.dxvParameters.guidRecordDevice );
  475. }
  476. if( !CheckFullDuplex( &rtInfo.dxvParameters ) )
  477. {
  478. goto EXIT;
  479. }
  480. // Startup thread which handles connects etc.
  481. VoiceManager_Start( &rtInfo );
  482. // Display Dialog if Required
  483. if( !rtInfo.dxvParameters.fSilent )
  484. {
  485. MainDialog_Create( &rtInfo );
  486. }
  487. while( MsgWaitForMultipleObjects( 1, &rtInfo.hThreadDone, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0 )
  488. {
  489. bGotMsg = TRUE;
  490. while( bGotMsg )
  491. {
  492. bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
  493. if( bGotMsg )
  494. {
  495. if( rtInfo.hMainDialog == NULL || !IsDialogMessage(rtInfo.hMainDialog,&msg) )
  496. {
  497. TranslateMessage( &msg );
  498. DispatchMessage( &msg );
  499. }
  500. }
  501. }
  502. }
  503. VoiceManager_Stop( &rtInfo );
  504. EXIT:
  505. if( fRunTimeInit )
  506. {
  507. FreeRunTime( &rtInfo );
  508. }
  509. DNOSIndirectionDeinit();
  510. CoUninitialize();
  511. return 0;
  512. }