Microsoft DirectX 8.1 (C++)

Tutorial 7: Creating a Lobbyable Application

A lobby is an application whose primary purpose is to enable players to meet and arrange games. It involves two separate application:

In order for a game application to take full advantage of lobby launching, it must be able to communicate with the lobby client application. This tutorial extends Tutorial 6 and discusses how to use Microsoft® DirectPlay® 8.1 to make a peer-to-peer application "lobbyable." Much of this information also applies to client/server applications. For further information on DirectPlay lobby support, see DirectPlay Lobbies. The complete sample code for this tutorial is included with the Microsoft® DirectX® software development kit (SDK) and can be found at (SDK root)\Samples\Multimedia\DirectPlay\Tutorials\Tut07_LobbyLaunch.

 

Refer to the preceding tutorials for a discussion of the initial steps in the process.

Note  The error handling code for the examples in this document have been deleted for clarity. See the tutorial sample for a complete version of the code.

User's Guide

When you run this tutorial sample, a Microsoft® MS-DOS® command window opens and you have the choice to either Host or Connect.

If you choose Host, do the following:

  1. Enter a session name. A message prints on the screen telling you that you are "currently hosting."
  2. Choose to Send or Exit. If you choose Send, you will be prompted to enter a text string. If you choose Exit, the session ends.

If you choose Connect, do the following:

  1. Enter an IP address. If a session is found at that address, you will be connected. If the address does not exist or if no session is found at the address, the application prints error messages.
  2. Once connected, choose Send or Exit. If you choose Send, you are prompted to enter a text string. If you choose Exit, the session ends.

You can run this sample twice—once to host a session and once to connect. When connecting, enter your computer's IP address. Once connected, you can send messages between the host and the client applications. To test host migration, close the host application. The client application is notified that it is the new host.

Detecting a Lobby Launch

Once your application is launched, you must determine whether you were launched by a lobby, or by some other means. To detect a lobby launch, you must first create a DirectPlay lobbied application object (CLSID_DirectPlay8LobbiedApplication).

Once the lobbied application object has been created, you must initialize it by calling IDirectPlay8LobbiedApplication::Initialize. This call takes four parameters:

There is only one flag value that can be set, DPNINITIALIZE_DISABLEPARAMVAL. Setting this flag disables parameter validation for methods on this instance of the DirectPlay lobbied application object. While setting this flag improves your application's performance, you should only do so with an application that has been thoroughly tested.

After the call to IDirectPlay8LobbiedApplication::Initialize returns, examine the lobby handle. If your application was lobby-launched, the variable is set to a valid lobby handle. If your application was not lobby-launched, the lobby handle is set to NULL.

The following excerpt from the tutorial sample illustrates how to detect a lobby launch.

#include <dplay8.h>
#include <dplobby8.h>

BOOL  g_bLobbyLaunched = FALSE;   // TRUE if lobby launched

IDirectPlay8lobbiedApplication * g_pLobbiedApp = NULL;
.
.
.
hr = CoCreateInstance(CLSID_DirectPlay8LobbiedApplication, NULL, 
                      CLSCTX_INPROC_SERVER,
                      IID_IDirectPlay8LobbiedApplication, 
                      (LPVOID*) &g_pLobbyApp);
.
.
.
// Initialize the lobbied application object
hr = g_pLobbyApp->Initialize(NULL, LobbyAppMessageHandler, &g_hLobbyHandle, 0);

//Determine whether the application was lobby-launched
g_bLobbyLaunched = (g_hLobbyHandle != NULL);  

Handling the DPL_MSGID_CONNECT Message

If you were lobby launched, your lobbied application message handler receives a DPL_MSGID_CONNECT message following your call to IDirectPlay8LobbiedApplication::Initialize. This message carries with it a variety of information, including the ID that you use to send messages to the lobby client. When you process this message, you should call IDirectPlay8Peer::RegisterLobby. Doing so allows applications to automatically propagate game status to the lobby client application.

The following excerpt from the tutorial sample illustrates how to handle DPL_MSGID_CONNECT.

HRESULT WINAPI LobbyAppMessageHandler(PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer)
{
.
.
.
    switch (dwMessageId)
    {
    .
	.
	.
        case DPL_MSGID_CONNECT:
        {
            PDPL_MESSAGE_CONNECT pConnectMsg;
            DPNHANDLE	            g_hLobbyClient;
            IDirectPlay8Peer*       g_pDP;

            pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
            PDPL_CONNECTION_SETTINGS pSettings = pConnectMsg->pdplConnectionSettings;
            g_hLobbyClient = pConnectMsg->hConnectId;
            
            //Register with the lobby
            hr = g_pDP->RegisterLobby( g_hLobbyClient, g_pLobbiedApp, DPNLOBBY_REGISTER);
            
            //Check for connection settings            
            if( pSettings == NULL )
               {
                // There are no connection settings from the lobby
               }
            else
                {
                 // You have connection settings
				}
           

Note: Your message handler might receive the DPL_MSGID_CONNECT message before the IDirectPlay8LobbiedApplication::Initialize method returns. Your message handler should be prepared to handle the message appropriately.

Obtaining Connection Settings

If your application was lobby-launched, the lobby client has the option of providing you with connection settings. To determine whether you have been given connection settings, examine the DPL_CONNECTION_SETTINGS structure that accompanies the DPL_MSGID_CONNECT message. If no connection settings are specified, you must query the user. See Tutorial 1 for details.

The DPL_CONNECTION_SETTINGS structure also provides you with a variety of other information that you will need to begin the session, including:

Starting the Session

Once you have selected your service provider, start the session much like you would a non-lobbied peer-to-peer session. You should first create a DirectPlay peer object, and call IDirectPlay8Peer::SetPeerInfo to establish your player's name. You should make this method call synchronous by setting the DPNOP_SYNC flag. Otherwise, there is a risk that the method might not return before you attempt to connect to the session.

If the lobby has selected you as host, you need to start hosting the session by calling IDirectPlay8Peer::Host. The other players typically receive your address through their lobby clients and send you connection requests. If you are not the host, get the address of the session host from the DPL_CONNECTION_SETTINGS structure and call the IDirectPlay8Peer::Connect method to connect to the session.

From this point on, the session proceeds much like a non-lobbied session. See the preceding tutorials for further details.

Terminating a Lobbied Session

You should next call IDirectPlay8LobbiedApplication::Close to close the connection to the lobbied application object. If a DirectPlay peer object was successfully initialized you should close the object by calling IDirectPlay8Peer::Close; then release all active objects and terminate the application. See Tutorial 1 for further discussion.

Registering an Application as Lobbyable

An application must be registered before it can be properly lobby launched. You only need to register the application once, typically during your installation procedure. Registration provides DirectPlay with a variety of information about your application, including:

To register your application, you must create a DirectPlay lobbied application object and call IDirectPlay8LobbiedApplication::RegisterProgram. Do not attempt to manually enter application information in the registry. Failure to use IDirectPlay8LobbiedApplication::RegisterProgram might make your application nonportable and incompatible with later versions of DirectPlay.

The following excerpt from the tutorial sample illustrates how to register a lobbyable application.


	DPL_PROGRAM_DESC	dplDesc;
 
	ZeroMemory(&dplDesc, sizeof(DPL_PROGRAM_DESC));
	dplDesc.dwSize = sizeof(DPL_PROGRAM_DESC);
	dplDesc.guidApplication = g_guidApp; //The application GUID
	dplDesc.pwszApplicationName = L"MyApplicationName";
	dplDesc.pwszExecutableFilename = L"MyApp.exe";
	dplDesc.pwszExecutablePath = L"C:\...\MyAppFolder";

	hr = g_pLobbyApp->RegisterProgram(&dplDesc, 0);

When you uninstall a registered lobbyable application, you should unregister it. Your uninstall procedure should create a DirectPlay lobbied application object, and unregister the application by calling the IDirectPlay8LobbiedApplication::UnRegisterProgram method.

The following excerpt from the tutorial sample illustrates how to unregister a lobbyable application.

HRESULT UnRegister()
{
	HRESULT		hr = S_OK;
	hr = g_pLobbyApp->UnRegisterProgram(&g_guidApp, 0);
	return hr;
}