home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / bellhop / bellhop.cpp next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  44.6 KB  |  1,647 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1996-1997 Microsoft Corporation.  All Rights Reserved.
  4.  *
  5.  *  File:       bellhop.cpp
  6.  *  Content:    Simple lobby program using DirectPlay.
  7.  *
  8.  ***************************************************************************/
  9.  
  10. #define INITGUID
  11. #include "bellhop.h"
  12. #include "resource.h"
  13.  
  14. enum {
  15.     WM_USER_ADDSTRING    = WM_USER+257,    // window message to add string to chat string list
  16.     WM_USER_UPDATE                        // window message to update lobby display
  17. };
  18.  
  19. // globals
  20. HANDLE            ghReceiveThread = NULL;            // handle of receive thread
  21. DWORD            gidReceiveThread = 0;            // id of receive thread
  22. HANDLE            ghKillReceiveEvent = NULL;        // event used to kill receive thread
  23. HWND            ghMainWnd = NULL;                // main window
  24. HINSTANCE        ghInstance;                        // application instance
  25.  
  26. //EXTERNs
  27. BOOL FAR PASCAL DirectPlayEnumConnectionsCallback(    LPCGUID lpguidSP, LPVOID lpConnection, 
  28.                                                             DWORD dwSize, LPCDPNAME lpName, 
  29.                                                             DWORD dwFlags, LPVOID lpContext);
  30. HRESULT    GetConnection(HWND hWnd,  int idCombo, LPVOID *lplpConnection);
  31. HRESULT    GetConnectionSPGuid(HWND hWnd, int idCombo, GUID *lpGuidSP);
  32.  
  33.  
  34.  
  35. ///////////////////////////////////////////////////////////////////////////////////////
  36. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  37.                    LPSTR lpCmdLine, int nCmdShow )
  38. {
  39.     DPLAYINFO    DPInfo;
  40.     int            iResult = 0;
  41.     HRESULT        hr;
  42.  
  43.     ghInstance = hInstance;
  44.  
  45.     // Initialize COM library
  46.     hr = CoInitialize(NULL);
  47.     if FAILED(hr)
  48.         goto FAILURE;
  49.  
  50.     // setup the connection
  51.     hr = SetupConnection(hInstance, &DPInfo);
  52.     if FAILED(hr)
  53.         goto FAILURE;
  54.  
  55.     // show the chat window
  56.     iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_LOBBYDIALOG), NULL, (DLGPROC) LobbyWndProc, (LPARAM) &DPInfo);
  57.  
  58. FAILURE:
  59.     // shut down the connection
  60.     hr = ShutdownConnection(&DPInfo);
  61.  
  62.     // Uninitialize the COM library
  63.     CoUninitialize();
  64.  
  65.     return (iResult);
  66. }
  67.  
  68. ///////////////////////////////////////////////////////////////////////////////////////
  69. BOOL CALLBACK LobbyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  70. {
  71.     static LPDPLAYINFO    lpDPInfo;
  72.     DWORD                dwTextLen;
  73.  
  74.     switch(uMsg)
  75.     {
  76.  
  77.     case WM_INITDIALOG:
  78.         {
  79.             HDC hDC;
  80.             int xPixelsPerInch,
  81.                 yPixelsPerInch;
  82.             RECT rect;
  83.  
  84.             // Save the connection info pointer
  85.             lpDPInfo = (LPDPLAYINFO) lParam;
  86.  
  87.             // Get the dialog spacing info
  88.             hDC = GetDC(hWnd);
  89.             xPixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSX);
  90.             yPixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSY);
  91.             ReleaseDC(hWnd, hDC);
  92.             lpDPInfo->xSpacing = xPixelsPerInch / 8;
  93.             lpDPInfo->ySpacing = yPixelsPerInch / 8;
  94.             lpDPInfo->xHalfSplitWidth = xPixelsPerInch / 12;
  95.  
  96.             GetClientRect(hWnd, &rect);
  97.             lpDPInfo->xPaneSplit = ((rect.right - rect.left) - (2 * lpDPInfo->xSpacing )) / 3 
  98.                                     - lpDPInfo->xHalfSplitWidth;    
  99.  
  100.             // Create the tree control
  101.             lpDPInfo->lpGroupTree = new CGroupTree;
  102.             lpDPInfo->lpGroupTree->Init(    GetDlgItem(hWnd, IDT_MESSAGEVIEW), 
  103.                                             lpDPInfo->lpDirectPlay3A,
  104.                                             lpDPInfo->dpidPlayer);
  105.             lpDPInfo->lpGroupTree->Refresh();
  106.             lpDPInfo->lpGroupTree->CreatePlayer( lpDPInfo->dpidPlayer, NULL, lpDPInfo->dwPlayerFlags );
  107.  
  108.             // store global window
  109.             ghMainWnd = hWnd;
  110.  
  111.             // initiallize lobby
  112.             InitializeLobby(hWnd, lpDPInfo);
  113.  
  114.             OnSize( hWnd, lpDPInfo );
  115.         }
  116.         break;
  117.  
  118.     case WM_DESTROY:
  119.         ghMainWnd = NULL;
  120.         break;
  121.  
  122.     case WM_SIZE:
  123.         OnSize(hWnd, lpDPInfo);
  124.         break;
  125.  
  126.     case WM_LBUTTONDOWN:
  127.         lpDPInfo->bSplitMove = TRUE;
  128.         SetCapture(hWnd);
  129.         break;
  130.  
  131.     case WM_LBUTTONUP:
  132.         if (lpDPInfo->bSplitMove)
  133.         {
  134.             lpDPInfo->bSplitMove = FALSE;
  135.             ReleaseCapture();
  136.         }
  137.         else
  138.         {
  139.             lpDPInfo->lpGroupTree->OnLButtonUp();
  140.         }
  141.         break;
  142.  
  143.     case WM_MOUSEMOVE:
  144.         if(lpDPInfo->bSplitMove)
  145.         {
  146.             // track mouse movement while adjusting the divider
  147.             RECT    rect;
  148.             // change the value from unsigned to signed
  149.             int     x = (int)(short)LOWORD(lParam);
  150.  
  151.             GetClientRect(hWnd, &rect);
  152.             if (rect.left > x)
  153.             {
  154.                 x = rect.left;
  155.             }
  156.             else if (rect.right < x)
  157.             {
  158.                 x = rect.right;
  159.             }
  160.             lpDPInfo->xPaneSplit = (x - lpDPInfo->xHalfSplitWidth - (lpDPInfo->xSpacing * 2));
  161.             OnSize(hWnd, lpDPInfo);
  162.         }
  163.         else
  164.         {
  165.             lpDPInfo->lpGroupTree->OnMouseMove(LOWORD(lParam), HIWORD(lParam) );
  166.         }
  167.         break;
  168.  
  169.  
  170.     // this is a user-defined message used to add strings to the log window
  171.     case WM_USER_ADDSTRING:
  172.         // get length of text in log window
  173.         dwTextLen = SendDlgItemMessage(hWnd, IDC_LOGEDIT, WM_GETTEXTLENGTH,
  174.                                        (WPARAM) 0, (LPARAM) 0);
  175.  
  176.         // put selection at end
  177.         dwTextLen = SendDlgItemMessage(hWnd, IDC_LOGEDIT, EM_SETSEL,
  178.                                        (WPARAM) dwTextLen, (LPARAM) dwTextLen);
  179.  
  180.         // add string in lParam to log window
  181.         SendDlgItemMessage(hWnd, IDC_LOGEDIT, EM_REPLACESEL,
  182.                             (WPARAM) FALSE, (LPARAM) lParam);
  183.         GlobalFreePtr((LPVOID) lParam);
  184.         break;
  185.  
  186.  
  187.     case WM_COMMAND:
  188.         switch(LOWORD(wParam))
  189.         {
  190.         case ID_ROOT_CREATEGROUP:
  191.             DoCreateRoom(hWnd, lpDPInfo);
  192.             break;            
  193.  
  194.         case ID_GROUP_CONNECTIONSETTINGS:
  195.             DoGroupConnectionSettings(hWnd, lpDPInfo);
  196.             break;            
  197.  
  198.         case ID_DESTROYGROUP:
  199.             DoDeleteRoom(hWnd, lpDPInfo);
  200.             break;            
  201.  
  202.         case ID_PLAYERINGROUP_DELETEPLAYERFROMGROUP:
  203.             DoDeletePlayerFromGroup(hWnd, lpDPInfo);
  204.             break;            
  205.  
  206.         case ID_CREATEGROUPINGROUP:
  207.             DoCreateTable(hWnd, lpDPInfo);
  208.             break;            
  209.  
  210.         case ID_SHORTCUT_DELETEGROUPFROMGROUP:
  211.             DoDeleteTable(hWnd, lpDPInfo);
  212.             break;            
  213.  
  214.         case ID_GROUP_STARTSESSION:
  215.             DoLaunch(hWnd, lpDPInfo);
  216.             break;            
  217.  
  218.         case ID_PLAYER_SETPLAYERNAME:
  219.         case ID_PLAYERINGROUP_SETPLAYERNAME:
  220.         case ID_GROUP_SETGROUPNAME:
  221.             lpDPInfo->lpGroupTree->EditLabel();
  222.             break;            
  223.  
  224.         case IDC_SENDBUTTON:
  225.             SendChatMessage(hWnd, lpDPInfo);
  226.             break;            
  227.  
  228.         case IDCANCEL:
  229.             EndDialog(hWnd, FALSE);
  230.             break;
  231.  
  232.         case ID_ROOT_ENUMRECURSIVE:
  233.             lpDPInfo->lpGroupTree->Refresh( );
  234.              lpDPInfo->lpGroupTree->CreatePlayer( lpDPInfo->dpidPlayer, NULL, lpDPInfo->dwPlayerFlags );
  235.            break;
  236.  
  237.         case ID_ROOT_ENUMGROUPS:
  238.             lpDPInfo->lpGroupTree->Refresh( FALSE );
  239.              lpDPInfo->lpGroupTree->CreatePlayer( lpDPInfo->dpidPlayer, NULL, lpDPInfo->dwPlayerFlags );
  240.            break;
  241.  
  242.         }
  243.         break;
  244.  
  245.     case WM_NOTIFY :
  246.          return lpDPInfo->lpGroupTree->OnWM_NOTIFY( wParam, lParam );
  247.         break;
  248.  
  249.     case WM_MENUSELECT:
  250.         return FALSE;
  251.         break;
  252.     }
  253.  
  254.     // Allow for default processing
  255.     return FALSE;
  256. }
  257.  
  258. ///////////////////////////////////////////////////////////////////////////////////////
  259. HRESULT SetupConnection(HINSTANCE hInstance, LPDPLAYINFO lpDPInfo)
  260. {
  261.     HRESULT        hr;
  262.  
  263.     ZeroMemory(lpDPInfo, sizeof(DPLAYINFO));
  264.  
  265.     // create event used by DirectPlay to signal a message has arrived
  266.     lpDPInfo->hPlayerEvent = CreateEvent(NULL,        // no security
  267.                                          FALSE,        // auto reset
  268.                                          FALSE,        // initial event reset
  269.                                          NULL);        // no name
  270.     if (lpDPInfo->hPlayerEvent == NULL)
  271.     {
  272.         hr = DPERR_NOMEMORY;
  273.         goto FAILURE;
  274.     }
  275.  
  276.     // create event used to signal that the receive thread should exit
  277.     ghKillReceiveEvent = CreateEvent(NULL,        // no security
  278.                                      FALSE,        // auto reset
  279.                                      FALSE,        // initial event reset
  280.                                      NULL);        // no name
  281.     if (ghKillReceiveEvent == NULL)
  282.     {
  283.         hr = DPERR_NOMEMORY;
  284.         goto FAILURE;
  285.     }
  286.  
  287.     // create thread to receive player messages
  288.     ghReceiveThread = CreateThread(NULL,            // default security
  289.                                    0,                // default stack size
  290.                                    ReceiveThread,    // pointer to thread routine
  291.                                    lpDPInfo,        // argument for thread
  292.                                    0,                // start it right away
  293.                                    &gidReceiveThread);
  294.     if (ghReceiveThread == NULL)
  295.     {
  296.         hr = DPERR_NOMEMORY;
  297.         goto FAILURE;
  298.     }
  299.  
  300.     // if there is no lobby connection, ask the user for settings
  301.     hr = ConnectUsingDialog(hInstance, lpDPInfo);
  302.     if FAILED(hr)
  303.         goto FAILURE;
  304.  
  305.     return (DP_OK);    
  306.  
  307. FAILURE:
  308.     ShutdownConnection(lpDPInfo);
  309.  
  310.     return (hr);
  311. }
  312.  
  313. ///////////////////////////////////////////////////////////////////////////////////////
  314. HRESULT ShutdownConnection(LPDPLAYINFO lpDPInfo)
  315. {
  316.     if (ghReceiveThread)
  317.     {
  318.         // wake up receive thread and wait for it to quit
  319.         SetEvent(ghKillReceiveEvent);
  320.         WaitForSingleObject(ghReceiveThread, INFINITE);
  321.  
  322.         CloseHandle(ghReceiveThread);
  323.         ghReceiveThread = NULL;
  324.     }
  325.  
  326.     if (ghKillReceiveEvent)
  327.     {
  328.         CloseHandle(ghKillReceiveEvent);
  329.         ghKillReceiveEvent = NULL;
  330.     }
  331.  
  332.     if (lpDPInfo->lpDirectPlay3A)
  333.     {
  334.         if (lpDPInfo->dpidPlayer)
  335.         {
  336.             IDirectPlay3_DestroyPlayer(lpDPInfo->lpDirectPlay3A, lpDPInfo->dpidPlayer);
  337.             lpDPInfo->dpidPlayer = 0;
  338.         }
  339.         IDirectPlay3_Close(lpDPInfo->lpDirectPlay3A);
  340.         IDirectPlay3_Release(lpDPInfo->lpDirectPlay3A);
  341.         lpDPInfo->lpDirectPlay3A = NULL;
  342.  
  343.         IDirectPlayLobby_Release(lpDPInfo->lpDirectPlayLobby2A);
  344.         lpDPInfo->lpDirectPlayLobby2A = NULL;
  345.  
  346.     }
  347.  
  348.     if (lpDPInfo->hPlayerEvent)
  349.     {
  350.         CloseHandle(lpDPInfo->hPlayerEvent);
  351.         lpDPInfo->hPlayerEvent = NULL;
  352.     }
  353.  
  354.     if (lpDPInfo->lpGroupTree)
  355.     {
  356.         delete lpDPInfo->lpGroupTree;
  357.         lpDPInfo->lpGroupTree = NULL;
  358.     }
  359.     return (DP_OK);
  360. }
  361.  
  362. ///////////////////////////////////////////////////////////////////////////////////////
  363. DWORD WINAPI ReceiveThread(LPVOID lpThreadParameter)
  364. {
  365.     LPDPLAYINFO    lpDPInfo = (LPDPLAYINFO) lpThreadParameter;
  366.     HANDLE        eventHandles[2];
  367.  
  368.     eventHandles[0] = lpDPInfo->hPlayerEvent;
  369.     eventHandles[1] = ghKillReceiveEvent;
  370.  
  371.     // loop waiting for player events. If the kill event is signaled
  372.     // the thread will exit
  373.     while (WaitForMultipleObjects(2, eventHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
  374.     {
  375.         // receive any messages in the queue
  376.         ReceiveMessage(lpDPInfo);
  377.     }
  378.  
  379.     ExitThread(0);
  380.  
  381.     return (0);
  382. }
  383.  
  384. ///////////////////////////////////////////////////////////////////////////////////////
  385. HRESULT ReceiveMessage(LPDPLAYINFO lpDPInfo)
  386. {
  387.     DPID                idFrom, idTo;
  388.     LPVOID                lpvMsgBuffer;
  389.     DWORD                dwMsgBufferSize;
  390.     HRESULT                hr;
  391.  
  392.     lpvMsgBuffer = NULL;
  393.     dwMsgBufferSize = 0;
  394.  
  395.     // loop to read all messages in queue
  396.     do
  397.     {
  398.         // loop until a single message is successfully read
  399.         do
  400.         {
  401.             // read messages from any player, including system player
  402.             idFrom = 0;
  403.             idTo = 0;
  404.  
  405.             hr = IDirectPlay3_Receive(lpDPInfo->lpDirectPlay3A, &idFrom, &idTo, DPRECEIVE_ALL,
  406.                                       lpvMsgBuffer, &dwMsgBufferSize);
  407.  
  408.             // not enough room, so resize buffer
  409.             if (hr == DPERR_BUFFERTOOSMALL)
  410.             {
  411.                 if (lpvMsgBuffer)
  412.                     GlobalFreePtr(lpvMsgBuffer);
  413.  
  414.                 lpvMsgBuffer = GlobalAllocPtr(GHND, dwMsgBufferSize);
  415.                 if (lpvMsgBuffer == NULL)
  416.                     hr = DPERR_OUTOFMEMORY;
  417.             }
  418.         } while (hr == DPERR_BUFFERTOOSMALL);
  419.  
  420.         if ((SUCCEEDED(hr)) &&                            // successfully read a message
  421.             (dwMsgBufferSize >= sizeof(DPMSG_GENERIC)))    // and it is big enough
  422.         {
  423.             // update the tree view UI.
  424.             lpDPInfo->lpGroupTree->Update( lpvMsgBuffer );
  425.  
  426.             // check for system message
  427.             if (idFrom == DPID_SYSMSG)
  428.             {
  429.                 HandleSystemMessage(lpDPInfo, (LPDPMSG_GENERIC) lpvMsgBuffer,
  430.                                     dwMsgBufferSize, idFrom, idTo);
  431.             }
  432.             else
  433.             {
  434.                 HandleApplicationMessage(lpDPInfo, (LPDPMSG_GENERIC) lpvMsgBuffer,
  435.                                          dwMsgBufferSize, idFrom, idTo);
  436.             }
  437.         }
  438.     } while (SUCCEEDED(hr));
  439.  
  440.     // free any memory we created
  441.     if (lpvMsgBuffer)
  442.         GlobalFreePtr(lpvMsgBuffer);
  443.  
  444.     return (DP_OK);
  445. }
  446.  
  447. ///////////////////////////////////////////////////////////////////////////////////////
  448. void HandleApplicationMessage(LPDPLAYINFO lpDPInfo, LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize,
  449.                               DPID idFrom, DPID idTo)
  450. {
  451.     // Any messages received from the lobby server would be handled here.
  452.     // In this case, we don't have any
  453. }
  454.  
  455. ///////////////////////////////////////////////////////////////////////////////////////
  456. void HandleSystemMessage(LPDPLAYINFO lpDPInfo, LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize,
  457.                          DPID idFrom, DPID idTo)
  458. {
  459.     LPSTR        lpszStr = NULL;
  460.  
  461.     // The body of each case is there so you can set a breakpoint and examine
  462.     // the contents of the message received.
  463.     switch (lpMsg->dwType)
  464.     {
  465.     case DPSYS_STARTSESSION:
  466.         {
  467.             LPDPMSG_STARTSESSION    lp = (LPDPMSG_STARTSESSION) lpMsg;
  468.  
  469.             HandleStartSession(lp->lpConn, lpDPInfo);
  470.         }
  471.         break;
  472.  
  473.     case DPSYS_CREATEPLAYERORGROUP:
  474.         {
  475.             LPDPMSG_CREATEPLAYERORGROUP        lp = (LPDPMSG_CREATEPLAYERORGROUP) lpMsg;
  476.             LPSTR                            lpszName, lpszDisplayFormat;
  477.             
  478.             if (lp->dwPlayerType == DPPLAYERTYPE_PLAYER)
  479.                 lpszDisplayFormat = "Player \"%s\" created\r\n";
  480.             else if (lp->dwPlayerType == DPPLAYERTYPE_GROUP)
  481.                 lpszDisplayFormat = "Group \"%s\" created\r\n";
  482.             else
  483.                 lpszDisplayFormat = "Unknown object \"%s\" created\r\n";
  484.  
  485.             // get pointer to player name
  486.             if (lp->dpnName.lpszShortNameA)
  487.                 lpszName = lp->dpnName.lpszShortNameA;
  488.             else
  489.                 lpszName = "unknown";
  490.  
  491.             // allocate space for string
  492.             lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(lpszDisplayFormat) +
  493.                                                    lstrlen(lpszName) + 1);
  494.             if (lpszStr == NULL)
  495.                 break;
  496.  
  497.             // build string
  498.             wsprintf(lpszStr, lpszDisplayFormat, lpszName);
  499.         }
  500.         break;
  501.  
  502.     case DPSYS_DESTROYPLAYERORGROUP:
  503.         {
  504.             LPDPMSG_DESTROYPLAYERORGROUP    lp = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
  505.             LPSTR                            lpszName, lpszDisplayFormat;
  506.             
  507.             if (lp->dwPlayerType == DPPLAYERTYPE_PLAYER)
  508.                 lpszDisplayFormat = "Player \"%s\" destroyed\r\n";
  509.             else if (lp->dwPlayerType == DPPLAYERTYPE_GROUP)
  510.                 lpszDisplayFormat = "Group \"%s\" destroyed\r\n";
  511.             else
  512.                 lpszDisplayFormat = "Unknown object \"%s\" destroyed\r\n";
  513.  
  514.             // get pointer to player name
  515.             if (lp->dpnName.lpszShortNameA)
  516.                 lpszName = lp->dpnName.lpszShortNameA;
  517.             else
  518.                 lpszName = "unknown";
  519.  
  520.             // allocate space for string
  521.             lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(lpszDisplayFormat) +
  522.                                                    lstrlen(lpszName) + 1);
  523.             if (lpszStr == NULL)
  524.                 break;
  525.  
  526.             // build string
  527.             wsprintf(lpszStr, lpszDisplayFormat, lpszName);
  528.         }
  529.         break;
  530.  
  531.     case DPSYS_ADDPLAYERTOGROUP:
  532.     case DPSYS_DELETEPLAYERFROMGROUP:
  533.         {
  534.             LPDPMSG_ADDPLAYERTOGROUP        lpAddMsg = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
  535.             LPDPMSG_DELETEPLAYERFROMGROUP    lpDeleteMsg = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
  536.             DPID                            dpidPlayer, dpidGroup;
  537.             LPSTR                            lpszPlayerName, lpszGroupName;
  538.             LPDPNAME                        lpPlayerName, lpGroupName;
  539.             LPSTR                            lpszDisplayFormat;
  540.             HRESULT                            hr;
  541.  
  542.             if (lpMsg->dwType == DPSYS_ADDPLAYERTOGROUP)
  543.             {
  544.                 dpidPlayer = lpAddMsg->dpIdPlayer;
  545.                 dpidGroup = lpAddMsg->dpIdGroup;
  546.                 lpszDisplayFormat = "Player \"%s\" added to group \"%s\"\r\n";
  547.             }
  548.             else
  549.             {
  550.                 dpidPlayer = lpDeleteMsg->dpIdPlayer;
  551.                 dpidGroup = lpDeleteMsg->dpIdGroup;
  552.                 lpszDisplayFormat = "Player \"%s\" removed from group \"%s\"\r\n";
  553.             }
  554.  
  555.             // get pointer to player name
  556.             hr = GetPlayerName(lpDPInfo->lpDirectPlay3A, dpidPlayer, &lpPlayerName);
  557.             if FAILED(hr)
  558.             {
  559.                 // A failure may mean that the player has been deleted
  560.                 // since we began processing this message
  561.                 lpPlayerName = NULL;
  562.             }
  563.  
  564.             if ((lpPlayerName) && (lpPlayerName->lpszShortNameA))
  565.                 lpszPlayerName = lpPlayerName->lpszShortNameA;
  566.             else
  567.                 lpszPlayerName = "unknown";
  568.  
  569.             // get pointer to group name
  570.             hr = GetGroupName(lpDPInfo->lpDirectPlay3A, dpidGroup, &lpGroupName);
  571.             if FAILED(hr)
  572.             {
  573.                 // A failure may mean that the group has been deleted
  574.                 // since we began processing this message
  575.                 lpGroupName = NULL;
  576.             }
  577.  
  578.             if ((lpGroupName) && (lpGroupName->lpszShortNameA))
  579.                 lpszGroupName = lpGroupName->lpszShortNameA;
  580.             else
  581.                 lpszGroupName = "unknown";
  582.  
  583.  
  584.             // allocate space for string
  585.             lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(lpszDisplayFormat) +
  586.                                                    lstrlen(lpszPlayerName) +
  587.                                                    lstrlen(lpszGroupName) + 1);
  588.             // build string
  589.             if (lpszStr)
  590.                 wsprintf(lpszStr, lpszDisplayFormat, lpszPlayerName, lpszGroupName);
  591.  
  592.             // free data we allocated
  593.             if (lpPlayerName)
  594.                 GlobalFreePtr(lpPlayerName);
  595.             if (lpGroupName)
  596.                 GlobalFreePtr(lpGroupName);
  597.         }
  598.         break;
  599.  
  600.     case DPSYS_ADDGROUPTOGROUP:
  601.     case DPSYS_DELETEGROUPFROMGROUP:
  602.         {
  603.             LPDPMSG_ADDGROUPTOGROUP        lpAddMsg = (LPDPMSG_ADDGROUPTOGROUP)lpMsg;
  604.             LPDPMSG_DELETEGROUPFROMGROUP    lpDeleteMsg = (LPDPMSG_DELETEGROUPFROMGROUP)lpMsg;
  605.             DPID                            dpidParentGroup, dpidGroup;
  606.             LPSTR                            lpszParentGroupName, lpszGroupName;
  607.             LPDPNAME                        lpParentGroupName, lpGroupName;
  608.             LPSTR                            lpszDisplayFormat;
  609.             HRESULT                            hr;
  610.  
  611.             if (lpMsg->dwType == DPSYS_ADDGROUPTOGROUP)
  612.             {
  613.                 dpidGroup = lpAddMsg->dpIdGroup;
  614.                 dpidParentGroup = lpAddMsg->dpIdParentGroup;
  615.                 lpszDisplayFormat = "Group \"%s\" added to group \"%s\"\r\n";
  616.             }
  617.             else
  618.             {
  619.                 dpidParentGroup = lpDeleteMsg->dpIdParentGroup;
  620.                 dpidGroup = lpDeleteMsg->dpIdGroup;
  621.                 lpszDisplayFormat = "Group \"%s\" removed from group \"%s\"\r\n";
  622.             }
  623.  
  624.             // get pointer to player name
  625.             hr = GetGroupName(lpDPInfo->lpDirectPlay3A, dpidParentGroup, &lpParentGroupName);
  626.             if FAILED(hr)
  627.                 lpParentGroupName = NULL;
  628.  
  629.             if ((lpParentGroupName) && (lpParentGroupName->lpszShortNameA))
  630.                 lpszParentGroupName = lpParentGroupName->lpszShortNameA;
  631.             else
  632.                 lpszParentGroupName = "unknown";
  633.  
  634.             // get pointer to group name
  635.             hr = GetGroupName(lpDPInfo->lpDirectPlay3A, dpidGroup, &lpGroupName);
  636.             if FAILED(hr)
  637.                 lpGroupName = NULL;
  638.  
  639.             if ((lpGroupName) && (lpGroupName->lpszShortNameA))
  640.                 lpszGroupName = lpGroupName->lpszShortNameA;
  641.             else
  642.                 lpszGroupName = "unknown";
  643.  
  644.             // allocate space for string
  645.             lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(lpszDisplayFormat) +
  646.                                                    lstrlen(lpszParentGroupName) +
  647.                                                    lstrlen(lpszGroupName) + 1);
  648.             // build string
  649.             if (lpszStr)
  650.                 wsprintf(lpszStr, lpszDisplayFormat, lpszGroupName, lpszParentGroupName );
  651.  
  652.             // free data we allocated
  653.             if (lpParentGroupName)
  654.                 GlobalFreePtr(lpParentGroupName);
  655.             if (lpGroupName)
  656.                 GlobalFreePtr(lpGroupName);
  657.         }
  658.         break;
  659.  
  660.     case DPSYS_SESSIONLOST:
  661.         {
  662.             LPDPMSG_SESSIONLOST lp = (LPDPMSG_SESSIONLOST)lpMsg;
  663.             LPSTR            szDisplayFormat = "Session lost.\r\n";
  664.  
  665.             // allocate space for string
  666.             lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(szDisplayFormat) + 1);
  667.             if (lpszStr == NULL)
  668.                 break;
  669.  
  670.             // build string
  671.             lstrcpy(lpszStr, szDisplayFormat);
  672.         }
  673.         break;
  674.  
  675.     case DPSYS_HOST:
  676.         {
  677.             LPDPMSG_HOST    lp = (LPDPMSG_HOST)lpMsg;
  678.             LPSTR            szDisplayFormat = "You have become the host\r\n";
  679.  
  680.             // allocate space for string
  681.             lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(szDisplayFormat) + 1);
  682.             if (lpszStr == NULL)
  683.                 break;
  684.  
  685.             // build string
  686.             lstrcpy(lpszStr, szDisplayFormat);
  687.  
  688.             // we are now the host
  689.             lpDPInfo->bIsHost = TRUE;
  690.         }
  691.         break;
  692.  
  693.     case DPSYS_SETPLAYERORGROUPDATA:
  694.         {
  695.             LPDPMSG_SETPLAYERORGROUPDATA lp = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
  696.         }
  697.         break;
  698.  
  699.     case DPSYS_SETPLAYERORGROUPNAME:
  700.         {
  701.             LPDPMSG_SETPLAYERORGROUPNAME lp = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
  702.         }
  703.         break;
  704.  
  705.     case DPSYS_CHAT:
  706.         {
  707.             LPDPMSG_CHAT    lp = (LPDPMSG_CHAT)lpMsg;
  708.             DWORD            dwSize = lstrlen( lp->lpChat->lpszMessageA ) + 12;
  709.                             //Allow extra room for "{whisper} ", in case this message
  710.                             //was sent just to me.
  711.  
  712.             // allocate space for string
  713.             lpszStr = (LPSTR) GlobalAllocPtr( GHND, dwSize );
  714.  
  715.             if (lpszStr == NULL)
  716.                 break;
  717.  
  718.             if (NULL == lp->idToGroup)
  719.             {
  720.                 //This message was sent just to me, not to a whole group
  721.                 lstrcpy( lpszStr, "{whisper} " );
  722.                 lstrcat( lpszStr, lp->lpChat->lpszMessageA );
  723.             }
  724.             else
  725.             {
  726.                 // build string
  727.                 lstrcpy(lpszStr, lp->lpChat->lpszMessageA);
  728.             }
  729.         }
  730.         break;
  731.  
  732.     }
  733.  
  734.     // post string to chat window
  735.     if (lpszStr)
  736.     {
  737.         // make sure window is still valid
  738.         if (ghMainWnd)
  739.             PostMessage(ghMainWnd, WM_USER_ADDSTRING, (WPARAM) 0, (LPARAM) lpszStr);
  740.         else
  741.             GlobalFreePtr(lpszStr);
  742.     }
  743.  
  744. }
  745.  
  746. ///////////////////////////////////////////////////////////////////////////////////////
  747. HRESULT GetPlayerName(LPDIRECTPLAY3A lpDirectPlay3A, DPID dpidPlayer,
  748.                       LPDPNAME *lplpName)
  749. {
  750.     LPDPNAME    lpName = NULL;
  751.     DWORD        dwNameSize;
  752.     HRESULT        hr;
  753.  
  754.     // get size of player name data
  755.     hr = IDirectPlay3_GetPlayerName(lpDirectPlay3A, dpidPlayer, NULL, &dwNameSize);
  756.     if (hr != DPERR_BUFFERTOOSMALL)
  757.         goto FAILURE;
  758.  
  759.     // make room for it
  760.     lpName = (LPDPNAME) GlobalAllocPtr(GHND, dwNameSize);
  761.     if (lpName == NULL)
  762.     {
  763.         hr = DPERR_OUTOFMEMORY;
  764.         goto FAILURE;
  765.     }
  766.  
  767.     // get player name data
  768.     hr = IDirectPlay3_GetPlayerName(lpDirectPlay3A, dpidPlayer, lpName, &dwNameSize);
  769.     if FAILED(hr)
  770.         goto FAILURE;
  771.  
  772.     // return pointer to name structure
  773.     *lplpName = lpName;
  774.  
  775.     return (DP_OK);
  776.  
  777. FAILURE:
  778.     if (lpName)
  779.         GlobalFreePtr(lpName);
  780.  
  781.     return (hr);
  782. }
  783.  
  784. ///////////////////////////////////////////////////////////////////////////////////////
  785. HRESULT GetGroupName(LPDIRECTPLAY3A lpDirectPlay3A, DPID dpidGroup,
  786.                      LPDPNAME *lplpName)
  787. {
  788.     LPDPNAME    lpName = NULL;
  789.     DWORD        dwNameSize;
  790.     HRESULT        hr;
  791.  
  792.     // get size of player name data
  793.     hr = IDirectPlay3_GetGroupName(lpDirectPlay3A, dpidGroup, NULL, &dwNameSize);
  794.     if (hr != DPERR_BUFFERTOOSMALL)
  795.         goto FAILURE;
  796.  
  797.     // make room for it
  798.     lpName = (LPDPNAME) GlobalAllocPtr(GHND, dwNameSize);
  799.     if (lpName == NULL)
  800.     {
  801.         hr = DPERR_OUTOFMEMORY;
  802.         goto FAILURE;
  803.     }
  804.  
  805.     // get player name data
  806.     hr = IDirectPlay3_GetGroupName(lpDirectPlay3A, dpidGroup, lpName, &dwNameSize);
  807.     if FAILED(hr)
  808.         goto FAILURE;
  809.  
  810.     // return pointer to name structure
  811.     *lplpName = lpName;
  812.  
  813.     return (DP_OK);
  814.  
  815. FAILURE:
  816.     if (lpName)
  817.         GlobalFreePtr(lpName);
  818.  
  819.     return (hr);
  820. }
  821.  
  822. ///////////////////////////////////////////////////////////////////////////////////////
  823. void InitializeLobbyGroupWindow(HWND hWnd, LPLOBBYGROUPCONTEXT lpContext)
  824. {
  825.     HRESULT            hr = DPERR_GENERIC;
  826.     ENUMCONNSTRUCT    enStruct;
  827.  
  828.     if (lpContext->dpidRoom == 0)
  829.         SetWindowText(hWnd, "Create Room");
  830.     else
  831.         SetWindowText(hWnd, "Create Table");
  832.  
  833.     // initialize max players
  834.     SetDlgItemInt(hWnd, IDC_MAXPLAYERSEDIT, 0, FALSE);
  835.  
  836.     // put all the DirectPlay applications in a combo box
  837.     lpContext->lpDPInfo->lpDirectPlayLobby2A->EnumLocalApplications(EnumApp, hWnd, 0);
  838.     SendDlgItemMessage(hWnd, IDC_APPCOMBO, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
  839.  
  840.     // put all the available connections in a combo box
  841.     enStruct.hWnd = hWnd;
  842.     enStruct.idCombo = IDC_GROUPCONNECTIONSPCOMBO;
  843.  
  844.     hr = IDirectPlay3_EnumConnections(    lpContext->lpDPInfo->lpDirectPlay3A, 
  845.                                         &BELLHOP_GUID, 
  846.                                         DirectPlayEnumConnectionsCallback,
  847.                                         &enStruct, DPCONNECTION_DIRECTPLAY );
  848.  
  849.     SendDlgItemMessage(hWnd, IDC_GROUPCONNECTIONSPCOMBO, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
  850.     return;
  851.  
  852. }
  853.  
  854. ///////////////////////////////////////////////////////////////////////////////////////
  855. HRESULT CreateLobbyGroup(HWND hWnd, LPLOBBYGROUPCONTEXT lpContext)
  856. {
  857.     CHAR                szShortName[MAXSTRLEN],
  858.                         szLongName[MAXSTRLEN],
  859.                         szPassword[MAXSTRLEN];
  860.     DPNAME                dpName;
  861.     DWORD                dwMaxPlayers;
  862.     DPID                dpID;
  863.     DPLCONNECTION        dplconn;
  864.     DPSESSIONDESC2        dpsess;
  865.     HRESULT                hr;
  866.     DWORD                dwFlags = 0;
  867.  
  868.     // get strings from dialog
  869.     GetDlgItemText(hWnd, IDC_SHORTNAMEEDIT, szShortName, MAXSTRLEN);
  870.     GetDlgItemText(hWnd, IDC_LONGNAMEEDIT, szLongName, MAXSTRLEN);
  871.  
  872.     if (BST_CHECKED == SendDlgItemMessage( hWnd, IDC_STAGINGAREA, BM_GETCHECK, 0, 0 ))
  873.     {
  874.         GetDlgItemText(hWnd, IDC_PASSWORDEDIT, szPassword, MAXSTRLEN);
  875.         dwMaxPlayers = GetDlgItemInt(hWnd, IDC_MAXPLAYERSEDIT, NULL, FALSE);
  876.         dwFlags = DPGROUP_STAGINGAREA;
  877.     }
  878.  
  879.     // build a dpname structure
  880.     ZeroMemory(&dpName, sizeof(DPNAME));
  881.     dpName.dwSize = sizeof(DPNAME);
  882.     dpName.lpszShortNameA = szShortName;
  883.     dpName.lpszLongNameA = szLongName;
  884.  
  885.     // create a root group
  886.     if (lpContext->dpidRoom == 0)
  887.     {
  888.         hr = IDirectPlay3_CreateGroup(lpContext->lpDPInfo->lpDirectPlay3A,
  889.                     &dpID, &dpName, NULL, 0, dwFlags);
  890.     }
  891.  
  892.     // create the table group
  893.     else
  894.     {
  895.         hr = IDirectPlay3_CreateGroupInGroup(    lpContext->lpDPInfo->lpDirectPlay3A,
  896.                                                 lpContext->dpidRoom, 
  897.                                                 &dpID, &dpName, 
  898.                                                 NULL, 0, dwFlags);
  899.     }
  900.  
  901.     if FAILED(hr)
  902.         goto FAILURE;
  903.  
  904.     if ( DPGROUP_STAGINGAREA & dwFlags )
  905.     {
  906.         
  907.         // Fill out the DPSESSIONDESC2 structure
  908.         ZeroMemory( &dpsess, sizeof(DPSESSIONDESC2) );
  909.         dpsess.dwSize = sizeof( DPSESSIONDESC2 );
  910.         dpsess.dwFlags = DPSESSION_KEEPALIVE | DPSESSION_MIGRATEHOST;
  911.  
  912.         CoCreateGuid(&(dpsess.guidInstance));
  913.  
  914.         GetComboBoxGuid(hWnd, IDC_APPCOMBO, &dpsess.guidApplication);
  915.  
  916.         dpsess.dwMaxPlayers = dwMaxPlayers;
  917.         dpsess.dwCurrentPlayers = 0;
  918.         dpsess.lpszSessionNameA = dpName.lpszShortNameA;
  919.         if (lstrlen(szPassword))
  920.             dpsess.lpszPasswordA = szPassword;
  921.  
  922.         // Fill out the DPLCONNECTION structure
  923.         ZeroMemory( &dplconn, sizeof(DPLCONNECTION) );
  924.         dplconn.dwSize = sizeof( DPLCONNECTION );
  925.         dplconn.lpSessionDesc = &dpsess;
  926.  
  927.         GetConnectionSPGuid(hWnd, IDC_GROUPCONNECTIONSPCOMBO, &dplconn.guidSP);
  928.  
  929.         // The rest of the DPLCONNECTION structure gets 
  930.         // filled in by the lobby
  931.  
  932.         hr = IDirectPlay3_SetGroupConnectionSettings(lpContext->lpDPInfo->lpDirectPlay3A,
  933.                                                      0, dpID, &dplconn );
  934.  
  935.         if FAILED(hr)
  936.             goto FAILURE;
  937.     }
  938.  
  939. FAILURE:
  940.     return (hr);
  941. }
  942.  
  943. ///////////////////////////////////////////////////////////////////////////////////////
  944. BOOL CALLBACK LobbyGroupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  945. {
  946.     LPLOBBYGROUPCONTEXT    lpContext = (LPLOBBYGROUPCONTEXT) GetWindowLong(hWnd, DWL_USER);
  947.  
  948.     switch(uMsg)
  949.     {
  950.       case WM_INITDIALOG:
  951.  
  952.             // context passed in lParam
  953.             lpContext = (LPLOBBYGROUPCONTEXT) lParam;
  954.  
  955.             // save the globals with the window
  956.             SetWindowLong(hWnd, DWL_USER, (LONG) lpContext);
  957.             
  958.             // Initialize dialog with appropriate information
  959.             InitializeLobbyGroupWindow(hWnd, lpContext);
  960.             break;
  961.  
  962.         case WM_DESTROY:
  963.             {
  964.                 WPARAM    index;
  965.                 LRESULT    lpData;
  966.  
  967.                 // destroy the GUID's stored with each app name
  968.                 index = 0;
  969.                 while (TRUE)
  970.                 {
  971.                     lpData = SendDlgItemMessage(hWnd, IDC_APPCOMBO, CB_GETITEMDATA, (WPARAM) index, 0);
  972.                     if ((lpData == CB_ERR) || (lpData == 0))
  973.                         break;
  974.  
  975.                     GlobalFreePtr((LPVOID) lpData);
  976.                     index += 1;
  977.                 }
  978.  
  979.                 // destroy the connection info in the combo box.
  980.                 index = 0;
  981.                 while (TRUE)
  982.                 {
  983.                     lpData = SendDlgItemMessage(hWnd, IDC_GROUPCONNECTIONSPCOMBO, CB_GETITEMDATA, (WPARAM) index, 0);
  984.                     if ((lpData == CB_ERR) || (lpData == 0))
  985.                         break;
  986.  
  987.                     GlobalFreePtr((LPVOID) lpData);
  988.                     index += 1;
  989.                 }
  990.             }
  991.             break;
  992.  
  993.         case WM_COMMAND:
  994.             switch(LOWORD(wParam))
  995.             {
  996.                 case IDOK:
  997.                     // save changes they made
  998.                     CreateLobbyGroup(hWnd, lpContext);
  999.                     // Return success
  1000.                     EndDialog(hWnd, TRUE);
  1001.  
  1002.                     break;
  1003.  
  1004.                 case IDCANCEL:
  1005.                     // Return failure
  1006.                     EndDialog(hWnd, FALSE);
  1007.  
  1008.                     break;
  1009.  
  1010.                 case IDC_STAGINGAREA:
  1011.                     {
  1012.                         int i = SendDlgItemMessage( hWnd, IDC_STAGINGAREA, BM_GETCHECK, 0, 0 );
  1013.                         EnableWindow( GetDlgItem( hWnd, IDC_PASSWORDEDIT ), (BST_CHECKED==i));
  1014.                         EnableWindow( GetDlgItem( hWnd, IDC_APPCOMBO ), (BST_CHECKED==i));
  1015.                         EnableWindow( GetDlgItem( hWnd, IDC_MAXPLAYERSEDIT ), (BST_CHECKED==i));
  1016.                         EnableWindow( GetDlgItem( hWnd, IDC_GROUPCONNECTIONSPCOMBO ), (BST_CHECKED==i));
  1017.                     }
  1018.                     break;
  1019.  
  1020.             }
  1021.  
  1022.             break;
  1023.     }
  1024.  
  1025.     // Allow for default processing
  1026.     return FALSE;
  1027. }
  1028.  
  1029. ///////////////////////////////////////////////////////////////////////////////////////
  1030. HRESULT DoGroupConnectionSettings(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1031. {
  1032.     LOBBYGROUPCONTEXT    context;
  1033.  
  1034.     context.lpDPInfo = lpDPInfo;
  1035.     context.dpidRoom = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection();
  1036.  
  1037.     if (DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_CONNECTIONSETTINGSDIALOG), hWnd,
  1038.                       (DLGPROC) ConnectionSettingsDialogProc, (LPARAM) &context))
  1039.     {
  1040.         // something changed
  1041.         // We could update a status bar here.
  1042.     }
  1043.  
  1044.     return (DP_OK);
  1045. }
  1046.  
  1047. ///////////////////////////////////////////////////////////////////////////////////////
  1048. HRESULT DoCreateRoom(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1049. {
  1050.     LOBBYGROUPCONTEXT    context;
  1051.  
  1052.     context.lpDPInfo = lpDPInfo;
  1053.     context.dpidRoom = (DPID) 0;
  1054.  
  1055.     if (DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_LOBBYGROUPDIALOG), hWnd,
  1056.                       (DLGPROC) LobbyGroupWndProc, (LPARAM) &context))
  1057.     {
  1058.         // something changed
  1059.         // We could update a status bar here.
  1060.     }
  1061.  
  1062.     return (DP_OK);
  1063. }
  1064.  
  1065. ///////////////////////////////////////////////////////////////////////////////////////
  1066. HRESULT DoDeleteRoom(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1067. {
  1068.     DPID                dpidRoom;
  1069.     HRESULT                hr = DP_OK;
  1070.  
  1071.     dpidRoom = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection();
  1072.  
  1073.     // delete the group
  1074.     hr = IDirectPlay3_DestroyGroup(lpDPInfo->lpDirectPlay3A, dpidRoom);
  1075.  
  1076.     return (hr);
  1077. }
  1078.  
  1079. ///////////////////////////////////////////////////////////////////////////////////////
  1080. HRESULT DoDeletePlayerFromGroup(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1081. {
  1082.     DPID                dpidRoom,
  1083.                         dpidPlayer;
  1084.     HRESULT                hr = DP_OK;
  1085.  
  1086.     dpidRoom = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelectionParent();
  1087.     dpidPlayer = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection();
  1088.  
  1089.     // delete the player from the group
  1090.     hr = IDirectPlay3_DeletePlayerFromGroup(lpDPInfo->lpDirectPlay3A, dpidRoom, dpidPlayer );
  1091.  
  1092.     return (hr);
  1093. }
  1094.  
  1095. ///////////////////////////////////////////////////////////////////////////////////////
  1096. HRESULT DoCreateTable(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1097. {
  1098.     LOBBYGROUPCONTEXT    context;
  1099.  
  1100.  
  1101.     context.lpDPInfo = lpDPInfo;
  1102.     context.dpidRoom = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection();
  1103.  
  1104.     DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_LOBBYGROUPDIALOG), hWnd,
  1105.                       (DLGPROC) LobbyGroupWndProc, (LPARAM) &context);
  1106.     return (DP_OK);
  1107. }
  1108.  
  1109. ///////////////////////////////////////////////////////////////////////////////////////
  1110. HRESULT DoDeleteTable(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1111. {
  1112.     DPID                dpidRoom,
  1113.                         dpidShortcut;
  1114.     HRESULT                hr = DP_OK;
  1115.  
  1116.     dpidRoom = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelectionParent();
  1117.     dpidShortcut = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection();
  1118.  
  1119.     // delete the player from the group
  1120.     hr = IDirectPlay3_DeleteGroupFromGroup(lpDPInfo->lpDirectPlay3A, dpidRoom, dpidShortcut );
  1121.     return (hr);
  1122. }
  1123.  
  1124. ///////////////////////////////////////////////////////////////////////////////////////
  1125. HRESULT DoLaunch(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1126. {
  1127.     DPID                dpidRoom;
  1128.     HRESULT                hr = DPERR_GENERIC;
  1129.  
  1130.     dpidRoom = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection();
  1131.  
  1132.     hr = IDirectPlay3_StartSession(lpDPInfo->lpDirectPlay3A, 0, dpidRoom); 
  1133.  
  1134.     return (hr);
  1135. }
  1136.  
  1137. ///////////////////////////////////////////////////////////////////////////////////////
  1138. HRESULT InitializeLobby(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1139. {
  1140.     DPNAME        name;
  1141.     DPID        dpID;
  1142.     HRESULT        hr = DP_OK;
  1143.  
  1144.     if (lpDPInfo->bIsHost)
  1145.     {    
  1146.         // add some groups to start with
  1147.         ZeroMemory(&name, sizeof(DPNAME));
  1148.         name.dwSize = sizeof(DPNAME);
  1149.  
  1150.         name.lpszShortNameA = "Golf Shack";
  1151.         hr = IDirectPlay3_CreateGroup(lpDPInfo->lpDirectPlay3A, &dpID, &name, NULL, 0, 0);
  1152.         if FAILED(hr)
  1153.             goto FAILURE;
  1154.  
  1155.         name.lpszShortNameA = "Monster Truck Rally";
  1156.         hr = IDirectPlay3_CreateGroup(lpDPInfo->lpDirectPlay3A, &dpID, &name, NULL, 0, 0);
  1157.         if FAILED(hr)
  1158.             goto FAILURE;
  1159.  
  1160.         name.lpszShortNameA = "Club Hellbender";
  1161.         hr = IDirectPlay3_CreateGroup(lpDPInfo->lpDirectPlay3A, &dpID, &name, NULL, 0, 0);
  1162.         if FAILED(hr)
  1163.             goto FAILURE;
  1164.     }
  1165.  
  1166. FAILURE:
  1167.     return (hr);
  1168. }
  1169.  
  1170. ///////////////////////////////////////////////////////////////////////////////////////
  1171. void LogString(LPSTR lpszDisplayFormat, LPSTR lpszDataStr)
  1172. {
  1173.     LPSTR    lpszStr;
  1174.  
  1175.         // allocate space for string
  1176.     lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(lpszDisplayFormat) +
  1177.                                            lstrlen(lpszDataStr) + 1);
  1178.     if (lpszStr == NULL)
  1179.         return;
  1180.  
  1181.     // build string
  1182.     wsprintf(lpszStr, lpszDisplayFormat, lpszDataStr);
  1183.  
  1184.     // post string to chat window
  1185.     // make sure window is still valid
  1186.     if (ghMainWnd)
  1187.         PostMessage(ghMainWnd, WM_USER_ADDSTRING, (WPARAM) 0, (LPARAM) lpszStr);
  1188.     else
  1189.         GlobalFreePtr(lpszStr);
  1190. }
  1191.  
  1192. ///////////////////////////////////////////////////////////////////////////////////////
  1193. HRESULT SendChatMessage(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1194. {
  1195.     LPSTR                lpszChatStr = NULL;
  1196.     LPSTR                lpszStr = NULL;
  1197.     LONG                lStrLen;
  1198.     HRESULT                hr;
  1199.     DPCHAT                dpc;
  1200.     DPID                dpidTarget;
  1201.  
  1202.     // get length of item text
  1203.     lStrLen = SendDlgItemMessage(hWnd, IDC_SENDEDIT, WM_GETTEXTLENGTH,
  1204.                                 (WPARAM) 0, (LPARAM) 0);
  1205.  
  1206.     // make room for it
  1207.     lpszChatStr = (LPSTR) GlobalAllocPtr(GHND, lStrLen + 1);
  1208.     if (lpszChatStr == NULL)
  1209.     {
  1210.         hr = DPERR_OUTOFMEMORY;
  1211.         goto FAILURE;
  1212.     }
  1213.  
  1214.     // get item text
  1215.     lStrLen = GetDlgItemText(hWnd, IDC_SENDEDIT, lpszChatStr, lStrLen + 1);
  1216.  
  1217.     // create string to display this text
  1218.     hr = NewChatString(lpDPInfo->lpDirectPlay3A, lpDPInfo->dpidPlayer, lpszChatStr, &lpszStr);
  1219.     if FAILED(hr)
  1220.         goto FAILURE;
  1221.  
  1222.     // setup the DPCHAT struct
  1223.     memset(&dpc, 0, sizeof(DPCHAT));
  1224.     dpc.dwSize = sizeof(DPCHAT);
  1225.     dpc.lpszMessageA = lpszStr;
  1226.     BRANCHSTRUCT    bs;
  1227.     
  1228.     dpidTarget = lpDPInfo->lpGroupTree->GetDPIDOfCurrentSelection( &bs );
  1229.  
  1230.     hr = IDirectPlay3_SendChatMessage(lpDPInfo->lpDirectPlay3A, lpDPInfo->dpidPlayer,
  1231.             dpidTarget, DPSEND_GUARANTEED, &dpc);
  1232.  
  1233.  
  1234.     if FAILED(hr)
  1235.         goto FAILURE;
  1236.  
  1237.     // display this string
  1238.     PostMessage(hWnd, WM_USER_ADDSTRING, (WPARAM) 0, (LPARAM) lpszStr);
  1239.     lpszStr = NULL;                        // set to NULL so we don't delete it below
  1240.  
  1241. FAILURE:
  1242.     if (lpszChatStr)
  1243.         GlobalFreePtr(lpszChatStr);
  1244.  
  1245.     if (lpszStr)
  1246.         GlobalFreePtr(lpszStr);
  1247.  
  1248.     SetDlgItemText(hWnd, IDC_SENDEDIT, "");
  1249.  
  1250.     return (hr);
  1251. }
  1252.  
  1253. ///////////////////////////////////////////////////////////////////////////////////////
  1254. HRESULT NewChatString(LPDIRECTPLAY3A lpDirectPlay3A, DPID dpidPlayer,
  1255.                       LPSTR lpszMsg, LPSTR *lplpszStr)
  1256. {
  1257.     LPDPNAME    lpName = NULL;
  1258.     LPSTR        lpszStr = NULL;
  1259.     LPSTR        lpszPlayerName;
  1260.     LPSTR        szDisplayFormat = "%s>\t%s\r\n";
  1261.     HRESULT        hr;
  1262.     
  1263.     // get name of player
  1264.     hr = GetPlayerName(lpDirectPlay3A, dpidPlayer, &lpName);
  1265.     if FAILED(hr)
  1266.         goto FAILURE;
  1267.  
  1268.     if (lpName->lpszShortNameA)
  1269.         lpszPlayerName = lpName->lpszShortNameA;
  1270.     else
  1271.         lpszPlayerName = "unknown";
  1272.  
  1273.     // allocate space for display string
  1274.     lpszStr = (LPSTR) GlobalAllocPtr(GHND, lstrlen(szDisplayFormat) +
  1275.                                            lstrlen(lpszPlayerName) +
  1276.                                            lstrlen(lpszMsg) + 1);
  1277.     if (lpszStr == NULL)
  1278.     {
  1279.         hr = DPERR_OUTOFMEMORY;
  1280.         goto FAILURE;
  1281.     }
  1282.  
  1283.     // build string
  1284.     wsprintf(lpszStr, szDisplayFormat, lpszPlayerName, lpszMsg);
  1285.  
  1286.     *lplpszStr = lpszStr;
  1287.     lpszStr = NULL;
  1288.  
  1289. FAILURE:
  1290.     if (lpszStr)
  1291.         GlobalFreePtr(lpszStr);
  1292.     
  1293.     if (lpName)
  1294.         GlobalFreePtr(lpName);
  1295.  
  1296.     return (hr);
  1297. }
  1298.  
  1299.  
  1300. ///////////////////////////////////////////////////////////////////////////////////////
  1301. HRESULT WaitForRunMsg( DWORD dwAppId, HANDLE hReceiveEvent, LPDWORD lpdwStatus, LPDPLAYINFO lpDPInfo )
  1302. {
  1303.     LPVOID              lpvMsg          = NULL;
  1304.     DWORD               dwMsgFlags;
  1305.     DWORD                dwMsgSize        = 0;
  1306.     BOOL                bContinue        = TRUE;
  1307.     BOOL                bNotFinished    = TRUE;
  1308.     HRESULT             hr                = E_FAIL;
  1309.  
  1310.     // For this function, we could have spun a seperate thread or integrated
  1311.     // the app/lobby client messaging into the main receive thread. 
  1312.     // For simplicity sake, the app/lobby client messaging loop is contained below. 
  1313.  
  1314.     // There are seven possible states that get us out of this function: 
  1315.     //    1. receive DPLSYS_DPLAYCONNECTSUCCEEDED
  1316.     //  2. receive DPLSYS_DPLAYCONNECTFAILED
  1317.     //  3. (Option) timeout waiting for hReceiveEvent
  1318.     //  4. DPERR_OUTOFMEMORY
  1319.     //  5. We receive an unexpected player-to-player msg.
  1320.     //  6. The app terminated.
  1321.     //  7. We get a system message we don't know about.
  1322.     //  8. We get an error calling receive
  1323.  
  1324.     *lpdwStatus = 0;
  1325.  
  1326.     while (bNotFinished)
  1327.     {
  1328.         if (hReceiveEvent)
  1329.         {
  1330.             if (WAIT_TIMEOUT == WaitForSingleObject( hReceiveEvent, 20000 ))
  1331.             {
  1332.                 hr = DPERR_TIMEOUT;
  1333.                 bNotFinished = FALSE;
  1334.                 break;
  1335.             }
  1336.         }
  1337.  
  1338.         do
  1339.         {
  1340.             hr =IDirectPlayLobby_ReceiveLobbyMessage(    lpDPInfo->lpDirectPlayLobby2A, 
  1341.                                                         0, dwAppId, &dwMsgFlags, 
  1342.                                                         lpvMsg, &dwMsgSize);
  1343.  
  1344.             switch( hr )
  1345.             {
  1346.                 case DPERR_BUFFERTOOSMALL:
  1347.                     {
  1348.                         if (lpvMsg)
  1349.                         {
  1350.                             GlobalFreePtr( lpvMsg );
  1351.                             lpvMsg = NULL;
  1352.                         }
  1353.  
  1354.                         lpvMsg = GlobalAllocPtr(GHND, dwMsgSize);
  1355.                         if(!lpvMsg)
  1356.                         {    hr = DPERR_OUTOFMEMORY;
  1357.                             goto end;
  1358.                         }
  1359.                     }
  1360.                     break;
  1361.  
  1362.                 case DP_OK:
  1363.                 {
  1364.                     // This better be a system message
  1365.                     if(!(dwMsgFlags & DPLAD_SYSTEM))
  1366.                     {
  1367.                         LPDPMSG_GENERIC lp = (LPDPMSG_GENERIC) lpvMsg;
  1368.                         hr = DPERR_GENERIC;
  1369.                         goto end;
  1370.                     }
  1371.  
  1372.                     if ( lpvMsg )
  1373.                     {
  1374.                         // Switch on the system message type
  1375.                         *lpdwStatus = *(LPDWORD)lpvMsg;
  1376.  
  1377.                         switch(*lpdwStatus)
  1378.                         {
  1379.                             case DPLSYS_APPTERMINATED:
  1380.                                 // App shut down
  1381.                                 bNotFinished = FALSE;
  1382.                                 bContinue = FALSE;
  1383.                                 break;
  1384.  
  1385.                             case DPLSYS_CONNECTIONSETTINGSREAD:
  1386.                                 break;
  1387.  
  1388.                             case DPLSYS_DPLAYCONNECTSUCCEEDED:
  1389.                             case DPLSYS_DPLAYCONNECTFAILED:
  1390.                                 bNotFinished = FALSE;
  1391.                                 break;
  1392.  
  1393.                             default:
  1394.                                 // RUNDPMSGLOG: Unexpected system message type
  1395.                                 hr = DPERR_GENERIC;
  1396.                                 bContinue = FALSE;
  1397.                                 bNotFinished = FALSE;
  1398.                                 break;
  1399.                         }
  1400.                     }
  1401.                 }
  1402.                 break;
  1403.  
  1404.                 case DPERR_NOMESSAGES:
  1405.                     // There are no messages left. 
  1406.                     // We need to stop and wait for another
  1407.                     bContinue = FALSE;
  1408.                     break;
  1409.  
  1410.                 default:
  1411.                     goto end;
  1412.                     break;
  1413.             }
  1414.  
  1415.         } while( bContinue );
  1416.     }
  1417.  
  1418. end:
  1419.     
  1420.     // Free resources
  1421.     GlobalFreePtr( lpvMsg );
  1422.  
  1423.     // Return 
  1424.     return (DPERR_NOMESSAGES == hr ? DP_OK : hr );
  1425. }
  1426.  
  1427. ///////////////////////////////////////////////////////////////////////////////////////
  1428. void HandleStartSession(LPDPLCONNECTION lpConn, LPDPLAYINFO lpDPInfo )
  1429. {
  1430.     DWORD                dwAppID;
  1431.     CHAR                szStr[MAXSTRLEN];
  1432.     HRESULT                hr;
  1433.     HANDLE                hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  1434.     DWORD                dwStatus = 0;
  1435.     
  1436.     if (hEvent)
  1437.     {
  1438.         // display name of application to launch
  1439.         hr = GetLocalAppName(lpDPInfo->lpDirectPlayLobby2A, 
  1440.                         &lpConn->lpSessionDesc->guidApplication, szStr);
  1441.  
  1442.         if FAILED(hr)
  1443.             lstrcpy(szStr, "unknown");
  1444.         
  1445.         LogString("Launching \"%s\"...\r\n", szStr);
  1446.         
  1447.         // Call RunApplication
  1448.         hr = IDirectPlayLobby_RunApplication(lpDPInfo->lpDirectPlayLobby2A, 0, &dwAppID, lpConn, hEvent );
  1449.  
  1450.         if FAILED(hr)
  1451.         {
  1452.             ErrorBox("Could not launch application because of error 0x%08X", hr);
  1453.         }
  1454.         else
  1455.         {
  1456.             // Wait for the app to launch
  1457.             hr = WaitForRunMsg( dwAppID, hEvent, &dwStatus, lpDPInfo );
  1458.         }
  1459.  
  1460.         CloseHandle( hEvent );
  1461.     }
  1462.  
  1463. } // HandleStartSession
  1464.  
  1465.  
  1466. ///////////////////////////////////////////////////////////////////////////////////////
  1467. BOOL FAR PASCAL EnumApp(LPCDPLAPPINFO lpAppInfo, LPVOID lpContext, DWORD dwFlags)
  1468. {
  1469.     HWND            hWnd = (HWND)lpContext;
  1470.     LRESULT            iIndex;
  1471.     LPGUID            lpGuid;
  1472.  
  1473.     // store application name in combo box
  1474.     iIndex = SendDlgItemMessage(hWnd, IDC_APPCOMBO, CB_ADDSTRING, 0, (LPARAM) lpAppInfo->lpszAppNameA);
  1475.     if (iIndex == LB_ERR)
  1476.         goto Failure;
  1477.  
  1478.     // make space for application GUID
  1479.     lpGuid = (LPGUID) GlobalAllocPtr(GHND, sizeof(GUID));
  1480.     if (lpGuid == NULL)
  1481.         goto Failure;
  1482.  
  1483.     // store pointer to GUID in combo box
  1484.     *lpGuid = lpAppInfo->guidApplication;
  1485.     SendDlgItemMessage(hWnd, IDC_APPCOMBO, CB_SETITEMDATA, (WPARAM) iIndex, (LPARAM) lpGuid);
  1486.  
  1487. Failure:
  1488.     return (TRUE);
  1489. }
  1490.  
  1491. ///////////////////////////////////////////////////////////////////////////////////////
  1492. HRESULT GetComboBoxGuid(HWND hWnd, LONG iDialogItem, LPGUID lpguidReturn)
  1493. {
  1494.     LONG    iIndex;
  1495.  
  1496.     // get index of selected item
  1497.     iIndex = SendDlgItemMessage(hWnd, iDialogItem, CB_GETCURSEL,
  1498.                                 (WPARAM) 0, (LPARAM) 0);
  1499.     if (iIndex == CB_ERR)
  1500.         return (DPERR_GENERIC);
  1501.  
  1502.     // get data associated with this item
  1503.     iIndex = SendDlgItemMessage(hWnd, iDialogItem, CB_GETITEMDATA,
  1504.                                 (WPARAM) iIndex, (LPARAM) 0);
  1505.     if ((iIndex == CB_ERR) || (iIndex == 0))
  1506.         return (DPERR_GENERIC);
  1507.  
  1508.     // data is a pointer to a guid
  1509.     *lpguidReturn = *((LPGUID) iIndex);
  1510.  
  1511.     return (DP_OK);
  1512. }
  1513.  
  1514. ///////////////////////////////////////////////////////////////////////////////////////
  1515. BOOL FAR PASCAL GetLocalAppNameCallback(LPCDPLAPPINFO lpAppInfo, LPVOID lpContext, DWORD dwFlags)
  1516. {
  1517.     LPAPPNAMECONTEXT    lpAppNameContext = (LPAPPNAMECONTEXT) lpContext;
  1518.  
  1519.     if (IsEqualGUID(lpAppInfo->guidApplication, lpAppNameContext->guidApplication))
  1520.     {
  1521.         lstrcpy(lpAppNameContext->szAppName, lpAppInfo->lpszAppNameA);
  1522.         return (FALSE);
  1523.     }
  1524.  
  1525.     return (TRUE);
  1526. }
  1527.  
  1528. ///////////////////////////////////////////////////////////////////////////////////////
  1529. HRESULT GetLocalAppName(LPDIRECTPLAYLOBBY lpIDPL,
  1530.                         LPGUID lpguidApplication, LPSTR lpszAppName)
  1531. {
  1532.     HRESULT            hr;
  1533.     APPNAMECONTEXT    AppNameContext;
  1534.  
  1535.     ZeroMemory(&AppNameContext, sizeof(APPNAMECONTEXT));
  1536.     AppNameContext.guidApplication = *lpguidApplication;
  1537.  
  1538.     // search local apps for matching guid
  1539.     hr = IDirectPlayLobby_EnumLocalApplications(lpIDPL, GetLocalAppNameCallback, &AppNameContext, 0);
  1540.     if FAILED(hr)
  1541.         goto FAILURE;
  1542.  
  1543.     // no local app found matching this guid
  1544.     if (lstrlen(AppNameContext.szAppName) == 0)
  1545.     {
  1546.         hr = DPERR_GENERIC;
  1547.         goto FAILURE;
  1548.     }
  1549.  
  1550.     // return name
  1551.     lstrcpy(lpszAppName, AppNameContext.szAppName);
  1552.  
  1553. FAILURE:
  1554.     return (hr);
  1555. }
  1556.  
  1557. ///////////////////////////////////////////////////////////////////////////////////////
  1558. void ErrorBox(LPSTR lpszErrorStr, HRESULT hr)
  1559. {
  1560.     char    szStr[MAXSTRLEN];
  1561.  
  1562.     wsprintf(szStr, lpszErrorStr, hr);
  1563.  
  1564.     MessageBox(NULL, szStr, "Error", MB_OK);
  1565. }
  1566.  
  1567. ///////////////////////////////////////////////////////////////////////////////////////
  1568. void OnSize(HWND hWnd, LPDPLAYINFO lpDPInfo)
  1569. {
  1570.     HDWP hDWP;
  1571.     RECT ClientRect;
  1572.     int Height;
  1573.     int xSpacing = lpDPInfo->xSpacing;
  1574.     int ySpacing = lpDPInfo->ySpacing;
  1575.     HWND hKeyTreeWnd;
  1576.     HWND hValueListWnd;
  1577.     HWND hMsgEditWnd;
  1578.     HWND hSendButtonWnd;
  1579.     int x;
  1580.     int dx;
  1581.     RECT SendButtonRect;
  1582.     int sendbuttonwidth;
  1583.     int sendbuttonheight;
  1584.  
  1585.     if (IsIconic(hWnd))
  1586.         return;
  1587.  
  1588.     if ((hDWP = BeginDeferWindowPos(4)) != NULL)
  1589.     {
  1590.         //  Data structure used when calling GetEffectiveClientRect (which takes into
  1591.         //  account space taken up by the toolbars/status bars).  First half of the
  1592.         //  pair is zero when at the end of the list, second half is the control id.
  1593.         int s_EffectiveClientRectData[] = {
  1594.             1, 0,                               //  For the menu bar, but is unused
  1595.             0, 0                                //  First zero marks end of data
  1596.         };
  1597.  
  1598.         GetEffectiveClientRect(hWnd, &ClientRect, s_EffectiveClientRectData);
  1599.         Height = ClientRect.bottom - ClientRect.top - (ySpacing * 5);
  1600.  
  1601.         // Resize the tree control
  1602.         hKeyTreeWnd = GetDlgItem( hWnd, IDT_MESSAGEVIEW );
  1603.  
  1604.         DeferWindowPos(hDWP, hKeyTreeWnd, NULL, 
  1605.             xSpacing, ClientRect.top + ySpacing, 
  1606.             lpDPInfo->xPaneSplit, Height, 
  1607.             SWP_NOZORDER | SWP_NOACTIVATE);
  1608.  
  1609.         x = lpDPInfo->xPaneSplit + lpDPInfo->xHalfSplitWidth * 2;
  1610.         dx = ClientRect.right - ClientRect.left - x - xSpacing;
  1611.  
  1612.         // Resize the logging window
  1613.         hValueListWnd = GetDlgItem( hWnd, IDC_LOGEDIT );
  1614.  
  1615.         DeferWindowPos(hDWP, hValueListWnd, NULL, 
  1616.             x, ClientRect.top+ySpacing, 
  1617.             dx, Height,
  1618.             SWP_NOZORDER | SWP_NOACTIVATE);
  1619.  
  1620.         // move the Send button, its size is constant
  1621.         hSendButtonWnd = GetDlgItem( hWnd, IDC_SENDBUTTON);
  1622.  
  1623.         GetWindowRect( hSendButtonWnd, &SendButtonRect );
  1624.         sendbuttonwidth = SendButtonRect.right - SendButtonRect.left; 
  1625.         sendbuttonheight = SendButtonRect.bottom - SendButtonRect.top; 
  1626.  
  1627.         DeferWindowPos(hDWP, hSendButtonWnd, NULL, 
  1628.             ClientRect.right - ( sendbuttonwidth + xSpacing ), 
  1629.             ClientRect.bottom - ( sendbuttonheight + ySpacing ), 
  1630.             sendbuttonwidth, 
  1631.             sendbuttonheight,
  1632.             SWP_NOZORDER | SWP_NOACTIVATE);
  1633.  
  1634.         // Resize and move the message edit control
  1635.         hMsgEditWnd = GetDlgItem( hWnd, IDC_SENDEDIT );
  1636.  
  1637.         DeferWindowPos(hDWP, hMsgEditWnd, NULL, 
  1638.             ClientRect.left + xSpacing, 
  1639.             ClientRect.bottom - ( sendbuttonheight + ySpacing ), 
  1640.             ClientRect.right - ClientRect.left - (sendbuttonwidth + xSpacing * 3), 
  1641.             sendbuttonheight,
  1642.             SWP_NOZORDER | SWP_NOACTIVATE);
  1643.  
  1644.         EndDeferWindowPos(hDWP);
  1645.     }
  1646. }
  1647.