/*========================================================================== * * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. * * File: dvretro.c * Content: Retrofit functions * History: * * Date By Reason * ==== == ====== * 08/12/99 rodtoll created it * 08/19/99 rodtoll Updated lobby launching to support retrofit * 08/20/99 rodtoll Modified to respond to shutdown request and * do proper lobby launch when in client mode. * 08/25/99 rodtoll Updated to use new GUID based compression selection * 09/14/99 rodtoll Updated for new Init call and SoundDeviceInfo usage. * 09/27(8)/99 rodtoll Updated with new interface * 09/28/99 rodtoll Updated for structure changes. * 09/29/99 rodtoll Updated for async enum, fixed bug with lobby launch * 10/15/99 rodtoll Massive code cleanup. Split into multiple files * rodtoll Minor fix, event was being released twice * 10/20/99 rodtoll Fixed name info for helper app * 11/02/99 rodtoll Bug #116677 - Can't use lobby clients that don't hang around * 11/04/99 pnewson Bug #115297 - launch device test if required * 11/12/99 rodtoll Added support for the new waveIN/waveOut flags and the * echo suppression flag. (Can specify them on command-line) * 12/01/99 rodtoll Bug #115783 - Regardless of device specified always adjusts volume * for default. Modified dpvhelp to allow user to select play/record * devices by using /SS switch. * 12/07/99 rodtoll Bug #122628 Make error messages silent when running in silent mode * rodtoll Bug #122979 Make invisible to end user * Now app must be run with /A to show an interface. * Also, unless /A or /L or /W are specified, the app will exit immediately. * Command-line help removed. * Auto-registration code removed for public version of app. * 02/15/2000 rodtoll Bug #132715 Voice is not working after rejoining the session * 03/03/2000 rodtoll Updated to handle alternative gamevoice build. * 06/28/2000 rodtoll Prefix Bug #38033 * ***************************************************************************/ #include "dxvhelppch.h" #define MAX_LOADSTRING 100 #define DPVHELP_WINDOWTITLE _T("DirectPlay Voice Chat") #define DPVHELP_WINDOWCLASS _T("DPVHELP") #define DPVHELP_PRIVATE_APPNAME _T("DirectPlay Voice Chat (Retrofit)") #define DPVHELP_PRIVATE_DESC _T("DirectPlay Voice Chat (Retrofit)") #define DPVHELP_PRIVATE_EXENAME _T("dpvhelp.exe") #define DPVHELP_PRIVATE_COMMANDLINE _T("/L /S /SC03") #define DPVHELP_PRIVATE_FLAGS 0x80000002 #undef DPF_MODNAME #define DPF_MODNAME "InitializeRunTime" void InitializeRunTime( PDXVHELP_RTINFO prtInfo ) { prtInfo->hReceiveEvent = NULL; prtInfo->hThreadDone = CreateEvent( NULL, TRUE, FALSE, NULL ); prtInfo->hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL ); prtInfo->hGo = CreateEvent( NULL, FALSE, FALSE, NULL ); prtInfo->hMainDialog = NULL; prtInfo->dpidLocalPlayer = 0xFFFFFFFF; prtInfo->lVolumeHeight = 0; prtInfo->hInst = NULL; prtInfo->hMainWnd = NULL; prtInfo->dwNumClients = 0; prtInfo->lpdpLobby = NULL; prtInfo->lpdvClient = NULL; prtInfo->lpdvServer = NULL; prtInfo->lpdpDirectPlay = NULL; prtInfo->hLobbyEvent = NULL; } #undef DPF_MODNAME #define DPF_MODNAME "FreeRunTime" void FreeRunTime( PDXVHELP_RTINFO prtInfo ) { CloseHandle( prtInfo->hThreadDone ); CloseHandle( prtInfo->hShutdown ); CloseHandle( prtInfo->hGo ); } #undef DPF_MODNAME #define DPF_MODNAME "SetDefaultParameters" void SetDefaultParameters( PDXVHELP_PARAMETERS pParameters ) { pParameters->fHost = FALSE; pParameters->fLobbyLaunched = FALSE; pParameters->fSilent = TRUE; pParameters->dwSessionType = DVSESSIONTYPE_PEER; pParameters->guidCT = DPVCTGUID_DEFAULT; pParameters->lpszConnectAddress[0] = 0; pParameters->fAGC = TRUE; pParameters->fAdvancedUI = FALSE; pParameters->fWaitForSettings = FALSE; pParameters->lRecordVolume = DSBVOLUME_MAX; pParameters->fRegister = FALSE; pParameters->fUnRegister = FALSE; pParameters->fKill = FALSE; pParameters->fIgnoreLobbyDestroy = FALSE; pParameters->fAllowWaveOut = FALSE; pParameters->fForceWaveOut = FALSE; pParameters->fAllowWaveIn = FALSE; pParameters->fForceWaveIn = FALSE; pParameters->fEchoSuppression = FALSE; pParameters->fAutoSelectMic = TRUE; pParameters->guidPlaybackDevice = DSDEVID_DefaultVoicePlayback; pParameters->guidRecordDevice = DSDEVID_DefaultVoiceCapture; pParameters->fSelectCards = FALSE; pParameters->fStrictFocus = FALSE; pParameters->fDisableFocus = FALSE; } #undef DPF_MODNAME #define DPF_MODNAME "ProcessCommandLine" BOOL ProcessCommandLine( PSTR pstrCommandLine, PDXVHELP_PARAMETERS pParameters ) { PSTR pNextToken = NULL; pNextToken = _tcstok( pstrCommandLine, _T(" ") ); while( pNextToken != NULL ) { if( _tcsicmp( pNextToken, _T("/A") ) == 0 ) { pParameters->fAdvancedUI = TRUE; pParameters->fSilent = FALSE; } else if( _tcsicmp( pNextToken, _T("/ES" ) ) == 0 ) { pParameters->fEchoSuppression = TRUE; } else if( _tcsicmp( pNextToken, _T("/WOF") ) == 0 ) { pParameters->fForceWaveOut = TRUE; } else if( _tcsicmp( pNextToken, _T("/NAS") ) == 0 ) { pParameters->fAutoSelectMic = FALSE; } else if( _tcsicmp( pNextToken, _T("/WOA") ) == 0 ) { pParameters->fAllowWaveOut = TRUE; } else if( _tcsicmp( pNextToken, _T("/WIF") ) == 0 ) { pParameters->fForceWaveIn = TRUE; } else if( _tcsicmp( pNextToken, _T("/WIA") ) == 0 ) { pParameters->fAllowWaveIn = TRUE; } else if( _tcsicmp( pNextToken, _T("/ES") ) == 0 ) { pParameters->fEchoSuppression = TRUE; } else if( _tcsicmp( pNextToken, _T("/W") ) == 0 ) { pParameters->fLobbyLaunched = TRUE; pParameters->fWaitForSettings = TRUE; } else if( _tcsicmp( pNextToken, _T("/L") ) == 0 ) { pParameters->fLobbyLaunched = TRUE; pParameters->fWaitForSettings = FALSE; } else if( _tcsicmp( pNextToken, _T("/R") ) == 0 ) { pParameters->fRegister = TRUE; return FALSE; } else if( _tcsicmp( pNextToken, _T("/U") ) == 0 ) { pParameters->fUnRegister = TRUE; return FALSE; } else if( _tcsicmp( pNextToken, _T("/S") ) == 0 ) { pParameters->fSilent = TRUE; } else if( _tcsicmp( pNextToken, _T("/K") ) == 0 ) { pParameters->fKill = TRUE; return FALSE; } else if( _tcsicmp( pNextToken, _T("/I") ) == 0 ) { pParameters->fIgnoreLobbyDestroy = TRUE; } else if( _tcsicmp( pNextToken, _T("/GSM") ) == 0 ) { pParameters->guidCT = DPVCTGUID_GSM; } else if( _tcsicmp( pNextToken, _T("/SC03" ) ) == 0 ) { pParameters->guidCT = DPVCTGUID_SC03; } else if( _tcsicmp( pNextToken, _T("/SC06" ) ) == 0 ) { pParameters->guidCT = DPVCTGUID_SC06; } else if( _tcsicmp( pNextToken, _T("/VR12" ) ) == 0 ) { pParameters->guidCT = DPVCTGUID_VR12; } else if( _tcsicmp( pNextToken, _T("/ADPCM" ) ) == 0 ) { pParameters->guidCT = DPVCTGUID_ADPCM; } else if( _tcsicmp( pNextToken, _T("/NONE" ) ) == 0 ) { pParameters->guidCT = DPVCTGUID_NONE; } else if( _tcsicmp( pNextToken, _T("/TRUE" ) ) == 0 ) { pParameters->guidCT = DPVCTGUID_TRUESPEECH; } else if( _tcsicmp( pNextToken, _T("/SS") ) == 0 ) { pParameters->fSelectCards = TRUE; } else if( _tcsicmp( pNextToken, _T("/FS") ) == 0 ) { pParameters->fStrictFocus = TRUE; } else if( _tcsicmp( pNextToken, _T( "/FD" ) ) == 0 ) { pParameters->fDisableFocus = TRUE; } else { return FALSE; } pNextToken = _tcstok( NULL, _T(" ") ); } if( !pParameters->fAdvancedUI && !pParameters->fLobbyLaunched ) { DPFX(DPFPREP, DVF_ERRORLEVEL, "Can only run in test mode and lobby mode" ); return FALSE; } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "RegisterApplication" void RegisterApplication() { HRESULT hr; BOOL fFailed = FALSE; hr = DPVDX_DP_RegisterApplication( DPVHELP_PRIVATE_APPNAME, DPVHELP_PRIVATE_APPID, DPVHELP_PRIVATE_EXENAME, DPVHELP_PRIVATE_COMMANDLINE, DPVHELP_PRIVATE_DESC, DPVHELP_PRIVATE_FLAGS ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Unable to register private application"), FALSE ); MessageBox( NULL, _T("Registered Application"), DPVHELP_WINDOWTITLE, MB_OK ); } if( !fFailed ) { MessageBox( NULL, _T("Registered Application"), DPVHELP_WINDOWTITLE, MB_OK ); } } #undef DPF_MODNAME #define DPF_MODNAME "UnRegisterApplication" void UnRegisterApplication() { HRESULT hr; BOOL fFailed = FALSE; hr = DPVDX_DP_UnRegisterApplication( DPVHELP_PRIVATE_APPID ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Unable to un-register private application"), FALSE ); fFailed = TRUE; } if( !fFailed ) { MessageBox( NULL, _T("Un-Registered Application"), DPVHELP_WINDOWTITLE, MB_OK ); } } // // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // #undef DPF_MODNAME #define DPF_MODNAME "MainWindowProc" LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; TCHAR szHello[MAX_LOADSTRING]; switch (message) { case WM_SHOWWINDOW: break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage is only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // #undef DPF_MODNAME #define DPF_MODNAME "MyRegisterClass" ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; // CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)MainWindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX); wcex.hCursor = NULL; // LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; //(LPCSTR)IDC_TESTWIN; wcex.lpszClassName = DPVHELP_WINDOWCLASS; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_DIRECTX); return RegisterClassEx(&wcex); } // // FUNCTION: InitInstance(HANDLE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // #undef DPF_MODNAME #define DPF_MODNAME "CreateHiddenMainWindow" HWND CreateHiddenMainWindow(HINSTANCE hInstance, int nCmdShow ) { HRESULT hr; HWND hWnd; hWnd = CreateWindow(DPVHELP_WINDOWCLASS, DPVHELP_WINDOWTITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!hWnd) { hr = GetLastError(); return NULL; } ShowWindow(hWnd, SW_HIDE); UpdateWindow(hWnd); return hWnd; } #undef DPF_MODNAME #define DPF_MODNAME "CheckFullDuplex" BOOL CheckFullDuplex( PDXVHELP_PARAMETERS pParameters ) { PDIRECTPLAYVOICETEST lpdvSetup; HRESULT hr; hr = CoCreateInstance( DPVOICE_CLSID_DPVOICE, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceTest, (void **) &lpdvSetup ); if( FAILED( hr ) ) { DPVDX_DVERRDisplay( hr, _T("Create of setup interface failed"), pParameters->fSilent ); return FALSE; } hr = lpdvSetup->CheckAudioSetup( &pParameters->guidPlaybackDevice, &pParameters->guidRecordDevice, NULL, DVFLAGS_QUERYONLY ); if( FAILED( hr ) ) { if( pParameters->fSilent ) { lpdvSetup->Release(); return FALSE; } hr = lpdvSetup->CheckAudioSetup( &pParameters->guidPlaybackDevice, &pParameters->guidRecordDevice, NULL, 0 ); lpdvSetup->Release(); if( FAILED( hr ) ) { return FALSE; } } else { lpdvSetup->Release(); } return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "WinMain" int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { DWORD dwThreadID; DXVHELP_RTINFO rtInfo; BOOL bGotMsg = FALSE; MSG msg; HRESULT hr; INITCOMMONCONTROLSEX InitCC = {0}; BOOL bOK = FALSE; BOOL fRunTimeInit = FALSE; // Initialize COM hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if( FAILED( hr ) ) { return FALSE; } if( !DNOSIndirectionInit() ) { CoUninitialize(); return FALSE; } // Setup default parameters SetDefaultParameters( &rtInfo.dxvParameters ); // Process the command-line // // If this function returns false, we are to exit if( !ProcessCommandLine( lpCmdLine, &rtInfo.dxvParameters ) ) { if( rtInfo.dxvParameters.fRegister ) { RegisterApplication(); } else if( rtInfo.dxvParameters.fUnRegister ) { UnRegisterApplication(); } goto EXIT; } // Load common-controls InitCC.dwSize = sizeof InitCC; bOK = InitCommonControlsEx(&InitCC); // Register Window Class MyRegisterClass(hInstance); // Initialize Events InitializeRunTime( &rtInfo ); fRunTimeInit = TRUE; if( rtInfo.dxvParameters.fLobbyLaunched ) { SetEvent( rtInfo.hGo ); } // Perform application initialization: rtInfo.hMainWnd = CreateHiddenMainWindow(hInstance, nCmdShow); if( rtInfo.hMainWnd == NULL ) { goto EXIT; } rtInfo.hInst = hInstance; // If user wants to select the soundcard if( rtInfo.dxvParameters.fSelectCards ) { GetCardSettings( rtInfo.hInst, NULL, &rtInfo.dxvParameters.guidPlaybackDevice, &rtInfo.dxvParameters.guidRecordDevice ); } if( !CheckFullDuplex( &rtInfo.dxvParameters ) ) { goto EXIT; } // Startup thread which handles connects etc. VoiceManager_Start( &rtInfo ); // Display Dialog if Required if( !rtInfo.dxvParameters.fSilent ) { MainDialog_Create( &rtInfo ); } while( MsgWaitForMultipleObjects( 1, &rtInfo.hThreadDone, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0 ) { bGotMsg = TRUE; while( bGotMsg ) { bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); if( bGotMsg ) { if( rtInfo.hMainDialog == NULL || !IsDialogMessage(rtInfo.hMainDialog,&msg) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } } } VoiceManager_Stop( &rtInfo ); EXIT: if( fRunTimeInit ) { FreeRunTime( &rtInfo ); } DNOSIndirectionDeinit(); CoUninitialize(); return 0; }