//----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CDPlay8Client::UpdateConnectionInfo() { if( NULL == m_pDPlay ) return E_FAIL; // Update the DPN_CONNECTION_INFO every 1/2 second... float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME ); if( fCurTime - m_fLastUpdateConnectInfoTime > 0.5f ) { // Call GetConnectionInfo to get DirectPlay stats about connection ZeroMemory( &m_dpnConnectionInfo, sizeof(DPN_CONNECTION_INFO) ); m_dpnConnectionInfo.dwSize = sizeof(DPN_CONNECTION_INFO); m_pDPlay->GetConnectionInfo( &m_dpnConnectionInfo, 0 ); // Call GetSendQueueInfo to get DirectPlay stats about messages m_pDPlay->GetSendQueueInfo( &m_dwHighPriMessages, &m_dwHighPriBytes, DPNGETSENDQUEUEINFO_PRIORITY_HIGH ); m_pDPlay->GetSendQueueInfo( &m_dwNormalPriMessages, &m_dwNormalPriBytes, DPNGETSENDQUEUEINFO_PRIORITY_NORMAL ); m_pDPlay->GetSendQueueInfo( &m_dwLowPriMessages, &m_dwLowPriBytes, DPNGETSENDQUEUEINFO_PRIORITY_LOW ); m_fLastUpdateConnectInfoTime = fCurTime; } return S_OK; }
//----------------------------------------------------------------------------- // Name: Run() // Desc: Handles the message loop and calls FrameMove() and Render() when // idle. //----------------------------------------------------------------------------- INT CMyApplication::Run() { MSG msg; // Message loop to run the app while( TRUE ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { // Skip WM_KEYDOWN so they aren't handled by the dialog if( msg.message == WM_KEYDOWN ) continue; if( !IsDialogMessage( m_hWnd, &msg ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } if( msg.message == WM_QUIT ) { DestroyWindow( m_hWnd ); break; } } else { // Update the time variables m_fTime = DXUtil_Timer( TIMER_GETAPPTIME ); m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME ); // This app uses idle time processing for the game loop if( FAILED( FrameMove() ) ) SendMessage( m_hWnd, WM_DESTROY, 0, 0 ); if( FAILED( Render() ) ) SendMessage( m_hWnd, WM_DESTROY, 0, 0 ); Sleep( 20 ); } } FinalCleanup(); return (INT)msg.wParam; }
//----------------------------------------------------------------------------- // Name: Create() // Desc: Creates the window //----------------------------------------------------------------------------- HRESULT CMyApplication::Create( HINSTANCE hInstance ) { // Display the main dialog box. CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, StaticMsgProc ); if( NULL == m_hWnd ) return E_FAIL; // Initialize the application timer DXUtil_Timer( TIMER_START ); return S_OK; }
//----------------------------------------------------------------------------- // Name: Create() // Desc: Here's what this function does: // - Checks to make sure app is still active (if fullscreen, etc) // - Checks to see if it is time to draw with DXUtil_Timer, if not, it just returns S_OK // - Calls FrameMove() to recalculate new positions // - Calls Render() to draw the new frame // - Updates some frame count statistics // - Calls m_pd3dDevice->Present() to display the rendered frame. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::Create( HINSTANCE hInstance) { HRESULT hr; // Create the Direct3D object m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ); if( m_pD3D == NULL ) return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT ); // Build a list of Direct3D adapters, modes and devices. The // ConfirmDevice() callback is used to confirm that only devices that // meet the app's requirements are considered. m_d3dEnumeration.SetD3D( m_pD3D ); m_d3dEnumeration.ConfirmDeviceCallback = ConfirmDeviceHelper; if( FAILED( hr = m_d3dEnumeration.Enumerate() ) ) { SAFE_RELEASE( m_pD3D ); return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT ); } // Unless a substitute hWnd has been specified, create a window to // render into if( m_hWnd == NULL) { // Register the windows class WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance, LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ), LoadCursor( NULL, IDC_ARROW ), (HBRUSH)GetStockObject(WHITE_BRUSH), NULL, _T("D3D Window") }; RegisterClass( &wndClass ); // Set the window's initial style m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; HMENU hMenu = LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ); // Set the window's initial width RECT rc; SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight ); AdjustWindowRect( &rc, m_dwWindowStyle, ( hMenu != NULL ) ? true : false ); // Create the render window m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, m_dwWindowStyle, CW_USEDEFAULT, CW_USEDEFAULT, (rc.right-rc.left), (rc.bottom-rc.top), 0, hMenu, hInstance, 0 ); } // The focus window can be a specified to be a different window than the // device window. If not, use the device window as the focus window. if( m_hWndFocus == NULL ) m_hWndFocus = m_hWnd; // Save window properties m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE ); GetWindowRect( m_hWnd, &m_rcWindowBounds ); GetClientRect( m_hWnd, &m_rcWindowClient ); if( FAILED( hr = ChooseInitialD3DSettings() ) ) { SAFE_RELEASE( m_pD3D ); return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT ); } // Initialize the application timer DXUtil_Timer( TIMER_START ); // Initialize the app's custom scene stuff if( FAILED( hr = OneTimeSceneInit() ) ) { SAFE_RELEASE( m_pD3D ); return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT ); } // Initialize the 3D environment for the app if( FAILED( hr = Initialize3DEnvironment() ) ) { SAFE_RELEASE( m_pD3D ); return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT ); } // The app is ready to go Pause( false ); return S_OK; }
//----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CDPlay8Client::ReceiveHandler( void *pvContext, DWORD dwMessageType, void *pvMessage ) { // Increment our Active Thread Counter. EnterCriticalSection( &m_csThreadCountLock ); //Get the time when we entered the Message Handler FLOAT fStartTime = DXUtil_Timer( TIMER_GETAPPTIME ); m_wActiveThreadCount++; if(m_wActiveThreadCount > m_wMaxThreadCount) m_wMaxThreadCount = m_wActiveThreadCount; // Calculate an average. FLOAT fdiff = m_wActiveThreadCount - m_fAvgThreadCount; m_fAvgThreadCount += fdiff/8; LeaveCriticalSection( &m_csThreadCountLock ); switch( dwMessageType ) { case DPN_MSGID_RECEIVE: { PDPNMSG_RECEIVE pRecvData = (PDPNMSG_RECEIVE) pvMessage; // Update the throughput counter m_dwThroughputBytes += pRecvData->dwReceiveDataSize; if( m_pClient != NULL ) { m_pClient->OnPacket( pRecvData->dpnidSender, pRecvData->pReceiveData, pRecvData->dwReceiveDataSize ); } break; } case DPN_MSGID_TERMINATE_SESSION: { m_dwSessionLostReason = DISCONNNECT_REASON_UNKNOWN; PDPNMSG_TERMINATE_SESSION pTermMsg = (PDPNMSG_TERMINATE_SESSION) pvMessage; // The MazeServer passes a DWORD in pvTerminateData if // it disconnected us, otherwise it will be null. if( pTermMsg->pvTerminateData != NULL ) { DWORD* pdw = (DWORD*) pTermMsg->pvTerminateData; m_dwSessionLostReason = *pdw; } if( m_pClient != NULL ) m_pClient->OnSessionLost( m_dwSessionLostReason ); // Now that the session is lost we need to restart DirectPlay by calling // Close() and Init() on m_pDPlay, however this can not be // done in the DirectPlay message callback, so the main thread will // do this when IsSessionLost() returns TRUE m_bSessionLost = TRUE; break; } case DPN_MSGID_ENUM_HOSTS_RESPONSE: { PDPNMSG_ENUM_HOSTS_RESPONSE pEnumResponse = (PDPNMSG_ENUM_HOSTS_RESPONSE) pvMessage; EnumSessionCallback( pEnumResponse->pApplicationDescription, pEnumResponse->pAddressSender, pEnumResponse->pAddressDevice ); break; } } EnterCriticalSection( &m_csThreadCountLock ); m_wActiveThreadCount-- ; // Calculate an average. FLOAT fDiffTime = ( DXUtil_Timer( TIMER_GETAPPTIME ) - fStartTime ) - m_fAvgThreadTime; m_fAvgThreadTime += fDiffTime/8; //Get the Max time in the thread. if ( fDiffTime > m_fMaxThreadTime ) { m_fMaxThreadTime = fDiffTime; } LeaveCriticalSection( &m_csThreadCountLock ); return S_OK; }
//----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CDPlay8Client::JoinSession( DWORD num ) { HRESULT hr; IDirectPlay8Address* pHostAddress = NULL; IDirectPlay8Address* pDeviceAddress = NULL; if( m_pDPlay == NULL ) return E_FAIL; DXTRACE( TEXT("MazeClient: Trying to connect to server\n") ); DPN_APPLICATION_DESC dpnAppDesc; ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) ); dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC ); dpnAppDesc.guidApplication = StressMazeAppGUID; dpnAppDesc.guidInstance = m_Sessions[num].guidInstance; EnterCriticalSection( &m_csLock ); // Copy the host and device address pointers, and addref them. // If this is not done, then there is a rare chance that // EnumSessionCallback() may be called during the Connect() call // and destory the address before DirectPlay gets a chance to copy them. pHostAddress = m_pHostAddresses[num]; pHostAddress->AddRef(); pDeviceAddress = m_pDeviceAddresses[num]; pDeviceAddress->AddRef(); LeaveCriticalSection( &m_csLock ); // Connect to the remote host // The enumeration is automatically canceled after Connect is called if( FAILED( hr = m_pDPlay->Connect( &dpnAppDesc, // Application description pHostAddress, // Session host address pDeviceAddress, // Address of device used to connect to the host NULL, NULL, // Security descriptions & credientials (MBZ in DPlay8) NULL, 0, // User data & its size NULL, // Asynchronous connection context (returned with DPNMSG_CONNECT_COMPLETE in async handshaking) NULL, // Asynchronous connection handle (used to cancel connection process) DPNOP_SYNC ) ) ) // Connect synchronously { if( hr == DPNERR_NORESPONSE || hr == DPNERR_ABORTED ) goto LCleanup; // These are possible if the server exits while joining if( hr == DPNERR_INVALIDINSTANCE ) goto LCleanup; // This is possible if the original server exits and another server comes online while we are connecting DXTRACE_ERR_NOMSGBOX( TEXT("Connect"), hr ); goto LCleanup; } m_bSessionLost = FALSE; DXTRACE( TEXT("MazeClient: Connected to server. Enum automatically canceled\n") ); UpdateConnectionInfo(); m_fLastUpdateConnectInfoTime = DXUtil_Timer( TIMER_GETAPPTIME ); LCleanup: SAFE_RELEASE( pHostAddress ); SAFE_RELEASE( pDeviceAddress ); return hr; }