Presentation is loading. Please wait.

Presentation is loading. Please wait.

Creating a DirectX Project A DirectPLay Chat Program.

Similar presentations


Presentation on theme: "Creating a DirectX Project A DirectPLay Chat Program."— Presentation transcript:

1 Creating a DirectX Project A DirectPLay Chat Program

2 Setting up your Compiler for DirectX Install DirectX SDK Make sure your compiler has path to directx8/include Directx8/lib Directx8/samples/multimedia/common/src Directx8/samples/multimedia/common/incl ude

3 Create a new win 32 application with Visual C++ Under the Project Settings menu, select Link In the Object/Libraries edit box, enter winmm.lib and dplay.lib Select C/C++ tab From the Category drop down menu, select Code Generation In the Use Run-Time Library drop-down menu, select Multi-Threaded

4 Select OK Under the Project Menu, select Add To Project and then select Files. Browse to where you installed DirectX. Under Directx8/samples/multimedia/common/src, you will find dxutil.cpp. Select this file and then select OK. Repeat the step to add dxutil.h from Directx8/samples/multimedia/common/includ e

5 Now, create DpChat.cpp The add new header file called DPChat.h The files will contain global vars declaration, function prototypes, and preprocessor definitions

6 The DPChat Header File 1. #define INITGUID 2. #include 3. #include 4. #include 5. #include "DXUtil.h" 6. //----------------------------------------------------------------------------------- 7. // Windows Globals 8. //----------------------------------------------------------------------------------- 9. // Icon Resource 10. #define IDI_ICON1101 11. // ID's for child windows 12. #defineIDC_hBU_Join40001 13. #defineIDC_hLB_Output40002 14. #defineIDC_hBU_Host40004 15. #defineIDC_hEB_InputServerIP40005 16. #defineIDC_hEB_InputServerPort40006 17. #defineIDC_hEB_InputName40007 Initialize all GUID, must be defined at the beginning of all DirectX application Needs for DirectPlay Button used to join the session List box output text Button used to host the session Edit box to input host name Edit box to input host port Edit box to input player ’ s name

7 18. #defineIDC_hST_TextServerIP40008 19. #defineIDC_hST_TextServerPort40009 20. #defineIDC_hST_TextName40010 21. #defineIDC_hEB_InputField40011 22. // Handles to child windows 23. HWNDhBU_Join= NULL; 24. HWNDhBU_Host= NULL; 25. HWNDhLB_Output= NULL; 26. HWNDhEB_InputServerIP= NULL; 27. HWNDhEB_InputServerPort= NULL; 28. HWNDhEB_InputName= NULL; 29. HWNDhEB_InputField= NULL; 30. HWNDhST_TextServerIP= NULL; 31. HWNDhST_TextServerPort= NULL; 32. HWNDhST_TextName= NULL; 33. // Timer Ids 34. #define TIMERID_CONNECT_COMPLETE 1 35. // set the GUID, Needed to identify application 36. GUID DP_CHAT = { 0x2ae835d, 0x9179, 0x485f, { 0x83, 0x43, 0x90, 0x1d, 0x32, 0x7c, 0xe7, 0x94 } }; 37. // Class name & app name 38. LPCTSTRlpszApplicationName = "DPChat"; 39. LPCTSTRlpszTitle= "DPChat"; Static text Edit box to accept chat text Set Windows timer (see later) Run guidgen from command prompt

8 40. //----------------------------------------------------------------------------------- 41. // Direct Play Objects 42. //----------------------------------------------------------------------------------- 43. IDirectPlay8Peer* g_pDP; 44. IDirectPlay8Address* g_pDeviceAddress; 45. IDirectPlay8Address* g_pHostAddress; 46. DPNHANDLEg_hConnectAsyncOp; 47. DPNIDg_dpnidLocalPlayer = 0; 48. #define MAX_PLAYERS4 49. struct PLAYER_INFORMATION 50. { 51. boolbActive; 52. DPNIDdpnidPlayer; 53. charszPlayerName[32]; 54. }; 55. PLAYER_INFORMATIONPlayerInfo[MAX_PLAYERS]; 56. //----------------------------------------------------------------------------------- 57. // Multi-Threading Variables 58. //----------------------------------------------------------------------------------- 59. HANDLE g_hConnectCompleteEvent; 60. HRESULTg_hrConnectComplete; 61. CRITICAL_SECTION g_csModifyPlayer; Used for both join and host Is this slot being used? Player ’ s unique DirectPlay identifier

9 62. //----------------------------------------------------------------------------------- 63. // Miscellaneous Variables 64. //----------------------------------------------------------------------------------- 65. LONGg_lNumberOfActivePlayers = 0; 66. BOOLbHost = 0; 67. //----------------------------------------------------------------------------------- 68. // Packet Structures 69. //----------------------------------------------------------------------------------- 70. struct PACKET_CHAT 71. { 72. charszText[256]; 73. }; 74. //----------------------------------------------------------------------------------- 75. // Functions for our Windows Interface 76. //----------------------------------------------------------------------------------- 77. // Message Loop CallBack Function prototype ( REQUIRED FOR ALL WINDOWS PROGRAMS ) 78. LRESULT CALLBACK fnMessageProcessor (HWND, UINT, WPARAM, LPARAM); 79. // Function to display text in the output box 80. void vShowText(HWNDhChildHandle, char *szText); 81. // Function to setup display of GUI 82. void vCreateInterface(HWND hWnd,HINSTANCE hInstance);

10 83. // Function called when program exits, cleans up allocated objects 84. void vCleanup(void); 85. //----------------------------------------------------------------------------------- 86. // DirectPlay Functions 87. //----------------------------------------------------------------------------------- 88. // Function to initialize direct play system 89. HRESULT hrInitializeDirectPlay( HWND hWindow ); 90. // Function to send chat message 91. HRESULThrSendChatMessage(int player, char*szmessage); 92. // Function to handle all incoming Dplay messages 93. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer ); 94. // Function to host a game 95. HRESULThrHostGame( HWND hwnd ); 96. // Function to join a game 97. HRESULThrJoinGame( HWND hWnd ); 98. // Function called when a player joins the game 99. HRESULThrCreatePlayer( PVOID pvUserContext, PVOID pMsgBuffer ); 100. // Function called when a player leaves the game 101. HRESULThrDestroyPlayer( PVOID pvUserContext, PVOID pMsgBuffer );

11 DPChat.cpp (main()) 1. #include "dpchat.h" 2. // 3. // Function to Create the Window and Display it ( REQUIRED FOR ALL WINDOWS PROGRAMS ) 4. // 5. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 6. { 7. MSGmsg; 8. WNDCLASSEXwndclass; 9. HWNDhWnd; 10. HRESULThReturn; 11. // Set up window attributes 12. wndclass.cbSize= sizeof(wndclass); 13. wndclass.style= CS_HREDRAW | CS_VREDRAW; 14. wndclass.lpfnWndProc= fnMessageProcessor; 15. wndclass.cbClsExtra= 0; 16. wndclass.cbWndExtra= 0;

12 17. wndclass.hInstance= hInstance; 18. wndclass.hIcon= LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON1) ); 19. wndclass.hCursor= LoadCursor( NULL, IDC_ARROW ); 20. wndclass.hbrBackground= (HBRUSH)(COLOR_WINDOW); 21. wndclass.lpszMenuName= NULL; 22. wndclass.lpszClassName= lpszApplicationName;// Registered Class Name 23. wndclass.hIconSm= LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON1) ); 24. 25. if( RegisterClassEx( &wndclass ) == 0 ) { 26. // Do error logic here 27. exit(1); 28. }

13 29. // Create the main window 30. hWnd = CreateWindow(lpszApplicationName,// Application Name 31. lpszTitle, // Name Displayed on Title Bar 32. WS_OVERLAPPEDWINDOW, 33. 100, 34. 100, 35. 400, 36. 340, 37. NULL, 38. NULL, 39. hInstance, 40. NULL ); 41. // Create Child Objects 42. vCreateInterface(hWnd,hInstance); 43. 44. ShowWindow(hWnd, nCmdShow); 45. UpdateWindow(hWnd);

14 46. // Initialize Direct Play 47. hReturn = hrInitializeDirectPlay( hWnd ); 48. if( FAILED(hReturn) ) { 49. vCleanup(); 50. exit(1); 51. } 52. 53. // Process messages until the program is terminated 54. while( GetMessage ( &msg, NULL, 0, 0 ) ) 55. { 56. TranslateMessage( &msg ); 57. DispatchMessage( &msg ); 58. } 59. 60. return(msg.wParam); 61. } Not using PeekMessage() in this example

15 vCreateInterface(hWnd,hInstance) 1. void vCreateInterface(HWND hWnd,HINSTANCE hInstance) 2. { 3. // Server IP Text 4. hST_TextServerIP = CreateWindow( 5. "static","Server IP", 6. WS_CHILD | SS_CENTER | WS_VISIBLE, 7. 5, 8. 5, 9. 120, 10. 28, 11. hWnd,(HMENU)IDC_hST_TextServerIP,hInstance,NULL);

16 12. // Port Text 13. hST_TextServerPort = CreateWindow( 14. "static","Port", 15. WS_CHILD | SS_CENTER | WS_VISIBLE, 16. 125, 17. 5, 18. 50, 19. 28, 20. hWnd,(HMENU)IDC_hST_TextServerPort,hInstance,NULL); 21. 22. // Name Text 23. hST_TextName = CreateWindow( 24. "static","Player Name", 25. WS_CHILD | SS_CENTER | WS_VISIBLE, 26. 250, 27. 5, 28. 135, 29. 28, 30. hWnd,(HMENU)IDC_hST_TextName,hInstance,NULL);

17 31. // Join Button 32. hBU_Join = CreateWindow( 33. "BUTTON", 34. "Join", 35. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 36. 325, 37. 280, 38. 60, 39. 28, 40. hWnd,(HMENU)IDC_hBU_Join,hInstance,NULL); 41. 42. // Host Button 43. hBU_Host = CreateWindow( 44. "BUTTON", 45. "Host", 46. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 47. 325, 48. 240, 49. 60, 50. 28, 51. hWnd,(HMENU)IDC_hBU_Host,hInstance,NULL);

18 52. // Output Window 53. hLB_Output = CreateWindowEx( 54. WS_EX_CLIENTEDGE, 55. "LISTBOX", 56. NULL, 57. WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | WS_BORDER, 58. 5, 59. 50, 60. 315, 61. 230, 62. hWnd,(HMENU)IDC_hLB_Output,hInstance,NULL); 63. 64. // Name 65. hEB_InputName = CreateWindowEx( 66. WS_EX_CLIENTEDGE, 67. "EDIT","Unnamed", 68. WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, 69. 250, 70. 20, 71. 135, 72. 28, 73. hWnd,(HMENU)IDC_hEB_InputName,hInstance,NULL);

19 74. // Server IP 75. hEB_InputServerIP = CreateWindowEx( 76. WS_EX_CLIENTEDGE, 77. "EDIT","192.168.0.2", 78. WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, 79. 5, 80. 20, 81. 120, 82. 28, 83. hWnd,(HMENU)IDC_hEB_InputServerIP,hInstance,NULL); 84. 85. // Server Port 86. hEB_InputServerPort = CreateWindowEx( 87. WS_EX_CLIENTEDGE, 88. "EDIT","6000", 89. WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, 90. 125, 91. 20, 92. 50, 93. 28, 94. hWnd,(HMENU)IDC_hEB_InputServerPort,hInstance,NULL);

20 95. // Edit field to enter chat messages into 96. hEB_InputField = CreateWindowEx( 97. WS_EX_CLIENTEDGE, 98. "EDIT",NULL, 99. WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL | ES_MULTILINE, 100. 5, 101. 280, 102. 315, 103. 28, 104. hWnd,(HMENU)IDC_hEB_InputField,hInstance,NULL); 105. }

21 Screen shot hST_TextServerIP hST_TextServerPort hST_TextName hBU_Join hBU_Host hLB_Output hEB_InputName hEB_InputServerIP hEB_InputServerPort hEB_InputField

22 Output to list box 1. void vShowText(HWNDhChildHandle, char *szText) 2. { 3. int Line; 4. 5. // add string to the listbox 6. SendMessage(hChildHandle,LB_ADDSTRING,0,(LPARAM)szText); 7. 8. // determine number of items in listbox 9. Line = SendMessage(hChildHandle,LB_GETCOUNT,0,0); 10. 11. // flag last item as the selected item, to scroll listbox down 12. SendMessage(hChildHandle,LB_SETCURSEL,Line-1,0); 13. 14. // unflag all items to eliminate negative highlite 15. SendMessage(hChildHandle,LB_SETCURSEL,-1,0); 16. }

23 fnMessageProcessor() 1. LRESULT CALLBACK fnMessageProcessor ( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) 2. { 3. charszMessage[256]; 4. charszCompMessage[256]; 5. HRESULThReturn; 6. 7. switch (iMsg) 8. { 9. case WM_COMMAND: 10. { 11. // Check for child window messages 12. switch(LOWORD(wParam)) 13. { 14. // Check if the user clicked the button 15. case IDC_hBU_Join: 16. hrJoinGame( hWnd ); 17. break; 18. case IDC_hBU_Host: 19. hrHostGame( hWnd ); 20. break; 21. }

24 22. switch(HIWORD(wParam)) 23. { 24. case EN_UPDATE: 25. // Get the text from the edit box 26. GetWindowText(hEB_InputField,szMessage,256); 27. // Check if they pressed enter 28. if( szMessage[strlen(szMessage)-1] == 10 ) { 29. // Get rid of trailing garbage 30. szMessage[strlen(szMessage)-2] = '\0'; 31. sprintf(szCompMessage," %s", PlayerInfo[0].szPlayerName, szMessage); 32. hReturn = hrSendChatMessage(- 1,szCompMessage); 33. // clear input field 34. SetWindowText(hEB_InputField,""); 35. } 36. } 37. break; 38. } 39. case WM_DESTROY: 40. // Cleanup System 41. vCleanup(); 42. // Exit out of Windows 43. PostQuitMessage(0); 44. break;

25 45. case WM_TIMER: 46. if( wParam == TIMERID_CONNECT_COMPLETE ) { 47. // Check if the message is telling us our connection is complete 48. if( WAIT_OBJECT_0 == WaitForSingleObject( g_hConnectCompleteEvent, 0 ) ) { 49. if( FAILED( g_hrConnectComplete ) ) { 50. vShowText(hLB_Output," >"); 51. } 52. else { 53. vShowText(hLB_Output," >"); 54. } 55. KillTimer( hWnd, TIMERID_CONNECT_COMPLETE ); 56. } 57. } 58. break; 59. 60. default: 61. return(DefWindowProc(hWnd, iMsg, wParam, lParam)); 62. } 63. return(0L); } So far, it ’ s all Windows GUI We set it earlier

26 hrInitializeDirectPlay() in WinMain 1. HRESULT hrInitializeDirectPlay( HWND hWindow ) 2. { 3. HRESULThReturn; 4. inti; 5. 6. // Initialize COM 7. hReturn = CoInitialize( NULL ); 8. if( FAILED(hReturn) ) { 9. MessageBox( hWindow, "Error Initializing COM", "DirectPlay Error", MB_ICONERROR ); 10. return hReturn; 11. } 12. 13. // Initialize critical sections for multi-threading 14. InitializeCriticalSection( &g_csModifyPlayer ); When players join sessions or leave sessions at the same time, the list of players won ’ t be corrupted

27 15. // Create IDirectPlay8Peer Object 16. if( FAILED( hReturn = CoCreateInstance( CLSID_DirectPlay8Peer, 17. NULL, 18. CLSCTX_INPROC_SERVER, 19. IID_IDirectPlay8Peer, 20. (LPVOID*) &g_pDP ) ) ) 21. MessageBox( hWindow, "Can't Create DPlayPeer", "DirectPlay Error", MB_ICONERROR ); 22. 23. // Init IDirectPlay8Peer Message Handler 24. if( FAILED( hReturn = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) ) { 25. MessageBox( hWindow, "Failed to Message Handler", "DirectPlay Error", MB_ICONERROR ); 26. return -1; 27. } 28. 29. // Create a device address 30. hReturn = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*) &g_pDeviceAddress ); 31. if( FAILED(hReturn) ) { 32. MessageBox( hWindow, "Failed to Create Device", "CoCreateInstance()", MB_ICONERROR ); 33. return -1; 34. }

28 35. // Set our service provider to TCP/IP 36. if( FAILED( hReturn = g_pDeviceAddress->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { 37. MessageBox( hWindow, "Failed to SetSP() for Device Address", "Invalid Param", MB_ICONERROR ); 38. return -1; 39. } 40. 41. // Create a host address 42. hReturn = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*) &g_pHostAddress ); 43. if( FAILED(hReturn) ) { 44. MessageBox( hWindow, "Failed to Create Host Address()", "Invalid Param", MB_ICONERROR ); 45. return -1; 46. } 47. // Set the host address to TCP/IP 48. if( FAILED( hReturn = g_pHostAddress->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { 49. MessageBox( hWindow, "Failed to SetSP() for Host Address", "Invalid Param", MB_ICONERROR ); 50. return -1; 51. } 52. // Create connection complete event for later use 53. g_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); See next page

29 54. vShowText(hLB_Output," >"); 55. // Init miscellaneous variables 56. for( i = 0 ; i < MAX_PLAYERS ; i++ ) { 57. PlayerInfo[i].bActive = 0; 58. } 59. 60. return S_OK; 61. } HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, //security attributes that can be inherited BOOL bManualReset, //or auto reset, depending on the boolean BOOL bInitialState, //event should start out signaled or not LPCTSTR lpName //name the event with this string );

30 DirectPlayMessageHandler() 1. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer ) 2. { 3. HRESULThReturn = S_OK; 4. 5. switch( dwMessageId ) 6. { 7. case DPN_MSGID_CREATE_PLAYER: 8. { 9. vShowText(hLB_Output,"Creating Player"); 10. hrCreatePlayer(pvUserContext,pMsgBuffer); 11. break; 12. } 13. 14. case DPN_MSGID_DESTROY_PLAYER: 15. { 16. hrDestroyPlayer(pvUserContext,pMsgBuffer); 17. break; 18. }

31 19. case DPN_MSGID_HOST_MIGRATE: 20. { 21. vShowText(hLB_Output,"Migrate Host"); 22. PDPNMSG_HOST_MIGRATE pHostMigrateMsg; 23. pHostMigrateMsg = (PDPNMSG_HOST_MIGRATE)pMsgBuffer; 24. 25. // Check to see if we are the new host 26. if( pHostMigrateMsg->dpnidNewHost == g_dpnidLocalPlayer ) { 27. vShowText(hLB_Output,"(HOSTING)"); 28. } 29. break; 30. } 31. 32. case DPN_MSGID_TERMINATE_SESSION: 33. { 34. vShowText(hLB_Output," "); 35. PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg; 36. pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer; 37. break; 38. } Received by the one who will take over at hosting. DirectPlay handles host change automatically If migration is not active and the host terminates the session, everyone gets disconnected

32 39. case DPN_MSGID_RECEIVE: 40. { 41. PDPNMSG_RECEIVE pReceiveMsg; 42. pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer; 43. 44. vShowText(hLB_Output,(char*)pReceiveMsg->pReceiveData); 45. 46. break; 47. } 48. 49. case DPN_MSGID_CONNECT_COMPLETE: 50. { 51. PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg; 52. pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer; 53. 54. g_hrConnectComplete = pConnectCompleteMsg->hResultCode; 55. SetEvent( g_hConnectCompleteEvent ); 56. break; 57. } 58. } 59. 60. return hReturn; 61. } Received whenever a chat message is sent. This msg type is used by all games to send custom messages Any player who joins a session successfully receives this message Put the event into a signaled state

33 hrHostGame() in fnMessageProcessor() 1. HRESULThrHostGame( HWND hWindow) 2. { 3. HRESULThReturn; 4. charszPeerName[256]; 5. charszSessionName[256]; 6. WCHARwszPeerName[256]; 7. WCHARwszSessionName[256]; 8. DPN_APPLICATION_DESCdnAppDesc; 9. charszPort[6]; 10. DWORDdwLength = 256; 11. DPN_PLAYER_INFOdpPlayerInfo; 12. DWORDdwPort = 9000; Used for player info

34 13. // Setup our player information 14. GetWindowText(hEB_InputName,szPeerName,36);// Get name from Window Edit Box 15. DXUtil_ConvertGenericStringToWide( wszPeerName, szPeerName ); 16. ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) ); 17. dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); 18. dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; //tell it to get info from pwszName 19. dpPlayerInfo.pwszName = wszPeerName; 20. 21. // Set us up to be non-asynchronous 22. if( FAILED( hReturn = g_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC ) ) ) { 23. MessageBox( hWindow, "Failed to SetPeerInfo()", "DirectPlay Error", MB_ICONERROR ); 24. return -1; 25. } 26. 27. // Setup the application description 28. sprintf(szSessionName,"%s's Game",szPeerName); 29. DXUtil_ConvertGenericStringToWide( wszSessionName, szSessionName ); 30. 31. ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) ); 32. dnAppDesc.dwSize= sizeof(DPN_APPLICATION_DESC); 33. dnAppDesc.guidApplication= DP_CHAT; 34. dnAppDesc.pwszSessionName= wszSessionName; 35. dnAppDesc.dwMaxPlayers= MAX_PLAYERS; 36. dnAppDesc.dwFlags= DPNSESSION_MIGRATE_HOST; Host is a player too, don ’ t forget Host can migrate

35 37. // Get Port from edit box 38. GetWindowText(hEB_InputServerPort,szPort,6); 39. // Convert the port string to a DWORD 40. dwPort = atol(szPort); 41. 42. // Add port number to address 43. hReturn = g_pDeviceAddress- >AddComponent(DPNA_KEY_PORT,&dwPort,sizeof(DWORD),DPNA_DATATYPE_DWORD); 44. if( hReturn != S_OK ) { 45. MessageBox( hWindow, "Failed to AddComponent()", "hrHostGame()", MB_ICONERROR ); 46. return -1; 47. } 48. 49. // Host the game 50. hReturn = g_pDP->Host(&dnAppDesc, 51. &g_pDeviceAddress, 52. 1, 53. NULL, 54. NULL, 55. NULL, 56. NULL ); A host needs port number to accept connection Application description address Host address Number of host address in &g_pDeviceAddress Player context Optional flags

36 57. if( FAILED( hReturn ) ) { 58. if( hReturn == DPNERR_INVALIDPARAM ) 59. MessageBox( hWindow, "Failed to Host()", "Invalid Param", MB_ICONERROR ); 60. else if( hReturn == DPNERR_INVALIDDEVICEADDRESS ) 61. MessageBox( hWindow, "Failed to Host()", "Invalid Device Address", MB_ICONERROR ); 62. else 63. MessageBox( hWindow, "Failed to Host()", "DirectPlay Error", MB_ICONERROR ); 64. return -1; 65. } 66. // Let us know we are the host 67. bHost = 1; 68. 69. vShowText(hLB_Output," "); 70. 71. return hReturn; 72. }

37 hrCreatePlayer() As soon as we finish the Host() function, the program receives a create player message. This function is actually called from DirectPlayMessageHandler() The message type is DPN_MSGID_CREATE_PLAYER

38 1. HRESULThrCreatePlayer( PVOID pvUserContext, PVOID pMsgBuffer ) 2. { 3. HRESULThReturn = S_OK; 4. PDPNMSG_CREATE_PLAYERpCreatePlayerMsg; 5. charstrName[256]; 6. charszOutput[256]; 7. DWORDdwSize = 0; 8. DPN_PLAYER_INFO*pdpPlayerInfo = NULL; 9. inti; 10. 11. // Get a Create Message pointer to the buffer 12. pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer; 13. 14. // Get the peer info and extract its name 15. hReturn = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 ); 16. if( FAILED(hReturn) && hReturn != DPNERR_BUFFERTOOSMALL ) { 17. hReturn = -1; 18. } 19. else { 20. // Allocate memory for the player info 21. pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ]; 22. 23. ZeroMemory( pdpPlayerInfo, dwSize ); 24. pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); 25. // Load the player info into the newly allocated data 26. hReturn = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 ); Typedef struct _DPNMSGH_CREATE_PLAYER{ DWORD dwSize;//size of this structure DPNID dpnidPlayer;//DPNID of new player PVOID pvPlayerContext } DPNMSGH_CREATE_PLAYER, * PDPNMSGH_CREATE_PLAYER; HRESULT GetPeerInfo( const DPNID dpnid, //peer id of the one we want to get info DPN_PLAYER_INFO*const pdpnPlayerInfo, //info will be stored here DWORD *const pdwSize, //size of the returned data const DWORD dwFlags // reserved data, always zero );

39 27. if( FAILED(hReturn) ) { 28. hReturn = -1; 29. } 30. else { 31. EnterCriticalSection( &g_csModifyPlayer ); 32. 33. // Convert player name to ANSI 34. DXUtil_ConvertWideStringToGeneric( strName, pdpPlayerInfo- >pwszName ); 35. // Add player to list 36. for( i = 0 ; i < MAX_PLAYERS ; i++ ) { 37. if( !PlayerInfo[i].bActive ) { 38. PlayerInfo[i].bActive = 1; 39. PlayerInfo[i].dpnidPlayer = pCreatePlayerMsg->dpnidPlayer; 40. strcpy(PlayerInfo[i].szPlayerName,strName); 41. break; 42. } 43. }

40 44. // Check if no free slot found 45. if( i == MAX_PLAYERS ) { 46. vShowText(hLB_Output,"No free slots in game!"); 47. } 48. // Check if we are adding ourselves 49. else if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL ) { 50. g_dpnidLocalPlayer = pCreatePlayerMsg- >dpnidPlayer; 51. sprintf(szOutput," Added Ourselves",i); 52. vShowText(hLB_Output,szOutput); 53. } 54. else { 55. sprintf(szOutput," Is In The Game",i,strName); 56. vShowText(hLB_Output,szOutput); 57. // Send them a welcoming message if we are the host 58. sprintf(szOutput,"Welcome to the game, %s!",strName); 59. if( bHost ) { 60. hrSendChatMessage(i,szOutput); 61. } 62. }

41 63. SAFE_DELETE_ARRAY( pdpPlayerInfo ); 64. 65. // Update the number of active players in a thread safe way 66. InterlockedIncrement( &g_lNumberOfActivePlayers ); 67. LeaveCriticalSection( &g_csModifyPlayer ); 68. } 69. } 70. 71. return hReturn; 72. } Clean memory Increment global var in a thread- safe way

42 hrJoinGame() in fnMessageProcessor() 1. HRESULT hrJoinGame( HWND hWnd ) 2. { 3. HRESULThReturn = S_OK; 4. WCHARwszHostName[256]; 5. WCHARwszPeerName[256]; 6. charszPeerName[256]; 7. charszIP[256]; 8. charszPort[256]; 9. DWORDdwPort; 10. DWORDdwLength = 256; 11. DPN_APPLICATION_DESCdpnAppDesc; 12. DPN_PLAYER_INFOdpPlayerInfo; 13. vShowText(hLB_Output,"Attempting Connection..."); 14. // Set the peer info 15. GetWindowText(hEB_InputName,szPeerName,36);// Get name from Window Edit Box 16. DXUtil_ConvertGenericStringToWide( wszPeerName, szPeerName );

43 17. ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) ); 18. dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); 19. dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; 20. dpPlayerInfo.pwszName = wszPeerName; 21. // Make this a synchronous call 22. if( FAILED( hReturn = g_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC ) ) ) { 23. vShowText(hLB_Output,"Failed to set peer info"); 24. return -1; 25. } 26. 27. // Prepare the application description 28. ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) ); 29. dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC ); 30. dpnAppDesc.guidApplication = DP_CHAT; 31. // Get IP from edit box 32. GetWindowText(hEB_InputServerIP,szIP,32); 33. // Get Port from edit box 34. GetWindowText(hEB_InputServerPort,szPort,6); 35. // Convert the IP to a wide string 36. DXUtil_ConvertGenericStringToWide( wszHostName, szIP ); 37. // Convert the port string to a DWORD 38. dwPort = atol(szPort);

44 39. // Add host name to address 40. hReturn = g_pHostAddress- >AddComponent(DPNA_KEY_HOSTNAME,wszHostName,(wcslen(wszHostName)+1)*size of(WCHAR),DPNA_DATATYPE_STRING); 41. if( hReturn != S_OK ) { 42. MessageBox( hWnd, "Failed to AddComponent()", "hrJoinGame()", MB_ICONERROR ); 43. return -1; 44. } 45. // Add port number to address 46. hReturn = g_pHostAddress- >AddComponent(DPNA_KEY_PORT,&dwPort,sizeof(DWORD),DPNA_DATATYPE_DWORD ); 47. if( hReturn != S_OK ) { 48. MessageBox( hWnd, "Failed to AddComponent()", "hrJoinGame()", MB_ICONERROR ); 49. return -1; 50. }

45 51. // Connect to the session 52. hReturn = g_pDP->Connect(&dpnAppDesc, 53. g_pHostAddress, 54. g_pDeviceAddress, 55. NULL, //reserved 56. NULL, //reserved 57. NULL, //optional user connect data 58. 0, // size of optional connect data 59. NULL, //optional context 60. NULL, //optional user-supplied context 61. &g_hConnectAsyncOp, //asynchronous handle 62. NULL); // flags 63. 64. if( hReturn != E_PENDING && FAILED(hReturn) ) { 65. vShowText(hLB_Output,"Failed to Connect"); 66. return -1; 67. } 68. SetTimer( hWnd, TIMERID_CONNECT_COMPLETE, 100, NULL ); 69. return(hReturn); 70. } 100 milliseconds timer, to signal program to check for a connection complete indicator-> so we don ’ t have to only loop waiting for connection

46 Joiner.. Gets at least 2 create messages, one for the host and one for the joiner If any other players are present, then you also get creation messages for them

47 hrSendChatMessage() HRESULThrSendChatMessage(int player, char *szmessage) { PACKET_CHATmsgChat; DPNHANDLEhAsync; DWORDdwLength = strlen(szmessage); DPN_BUFFER_DESC bufferDesc; // If no message to send, then just return if( dwLength == 0 ) return S_OK; // Copy the message to send into our packet strcpy(msgChat.szText,szmessage); // Set the size of the packet to send bufferDesc.dwBufferSize = sizeof(PACKET_CHAT) + dwLength; // Copy our packet into the send buffer bufferDesc.pBufferData = (BYTE*) &msgChat; // Send message to everyone including ourselves if -1 passed if( player == -1 ) g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1, 0, NULL, &hAsync, 0 ); // Send to specific player otherwise else g_pDP->SendTo( PlayerInfo[player].dpnidPlayer, &bufferDesc, 1, 0, NULL, &hAsync, 0 ); return S_OK; } Player to send, -1 for all players Called in fnMessageProcessor()

48 SendTo() HRESULT SendTo( const DPNID dpnid, //player to send to, use DPNIN_ALL_PLAYERS_GROUP // for all players DPN_BUFFER_DESC *const pBufferDesc, //the one loaded with message info const DWORD cBufferDesc, //no.of buffer you are sending DWORDdwTimeOut, // 0 for no time out void *const pvAsyncContext, //optional async context DPNHANDLE *const pAsyncHandle, //async handle const DWORD dwFlags );

49 Flags for SendTo() DPN_SEND_SYNC tells the program to process the send synchronously DPN_SEND_NOCOPY Keeps from making an internal copy DPN_SEND_NOCOMPLETE Prevent DPN_MSGID_SEND_NOCOMPLETE message from being received when a message is complete DPN_SEND_COMPLETEONPROCESS Sends a DPN_MSGID_SEND_NOCOMPLETE message to a message handler when the message is received and processed by the target. This can greatly slow down transmission. You must use DPN_GUARANTEED with this flag DPN_SEND_GUARANTEED Guarantees delivery of the message. Can slow down transmission

50 Flags for SendTo() cont … DPN_SEND_PRIORITY_HIGH DPN_SEND_PRIORITY_LOW DPN_SEND_NONSEQUENTIAL Target receives the message in order they arrive and not in order they were sent DPN_SEND_NOLOOPBACK Keeps you from sending a broadcast message back to yourself

51 hrDestroyPlayer() 1. HRESULThrDestroyPlayer( PVOID pvUserContext, PVOID pMsgBuffer ) 2. { 3. PDPNMSG_DESTROY_PLAYERpDestroyPlayerMsg; 4. HRESULThReturn = S_OK; 5. inti; 6. charszOutput[256]; 7. 8. // Get a Destroy Message pointer to the buffer 9. pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer; 10. 11. if( pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_NORMAL ) { 12. vShowText(hLB_Output,"Player Left Normally"); 13. } Why the player is destroyed

52 14. else if( pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_CONNECTIONLOST ) { 15. vShowText(hLB_Output,"Connection Lost w/Player"); 16. } 17. else if( pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_SESSIONTERMINATED ) { 18. vShowText(hLB_Output,"Player Terminated Session"); 19. } 20. else if( pDestroyPlayerMsg->dwReason == DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER ) { 21. vShowText(hLB_Output,"Player Kicked By Host"); 22. } 23. 24. // Update the number of active players in a thread safe way 25. InterlockedDecrement( &g_lNumberOfActivePlayers ); 26. EnterCriticalSection( &g_csModifyPlayer );

53 27. // Remove Player from list 28. for( i = 0 ; i < MAX_PLAYERS ; i++ ) { 29. if( PlayerInfo[i].bActive ) { 30. if( PlayerInfo[i].dpnidPlayer == pDestroyPlayerMsg- >dpnidPlayer ) { 31. PlayerInfo[i].bActive = 0; 32. sprintf(szOutput," Left The Game",i,PlayerInfo[i].szPlayerName); 33. vShowText(hLB_Output,szOutput); 34. break; 35. } 36. } 37. } 38. 39. LeaveCriticalSection( &g_csModifyPlayer ); 40. 41. return(hReturn); 42. }


Download ppt "Creating a DirectX Project A DirectPLay Chat Program."

Similar presentations


Ads by Google