Microsoft DirectX 9.0 SDK Update (Summer 2003) |
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:
- A lobby server application. This application is implemented by the lobby operator and resides on a remote computer.
- A lobby client application. This application is implemented by the lobby operator and runs on client systems. It allows the lobby server to communicate with client systems.
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® to make a peer-to-peer application "lobbyable". Much of this information also applies to client/server applications. For further information about DirectPlay lobby support, see DirectPlay Lobby. 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\C++\DirectPlay\Tutorials\Tut07_LobbyLaunch.
- User's Guide
- Detecting a Lobby Launch
- Handling the DPL_MSGID_CONNECT Message
- Obtaining Connection Settings
- Starting the Session
- Terminating a Lobbied Session
- Registering an Application as Lobbyable
Refer to the preceding tutorials for a discussion of the initial steps in the process:
- Tutorial 1: Creating a DirectPlay Object and Enumerating Service Providers
- Tutorial 2: Hosting a Session
- Tutorial 4: Connecting to a Session
- Tutorial 5: Sending Messages to Other Peers
- Tutorial 6: Handling Host Migration
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
This sample has the same user interface (UI) as Tutorial 6: Handling Host Migration. See the Users Guide in Tutorial 6: Handling Host Migration for how to use this sample.
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:
- A context value. This value is included with each message that the lobbied application object sends to your message handler.
- A pointer to your lobbied application message handling function. This is a standard DirectPlay message handler, which processes messages from the lobbied application object.
- A pointer to a lobby handle.
- A flag field.
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_pLobbyApp = 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. if( g_hLobbyHandle != NULL ) { // Attempt to host or connect to a session based on the // settings received from the lobby client. } else // The application was not lobby-launched.
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 identifier (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. }
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 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:
- A flag indicating whether you are to be the session host.
- A DPN_APPLICATION_DESC structure with a description of the session.
- The address of the host, unless you have been selected as host.
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:
- The application's unique globally unique identifier (GUID)
- The application's name
- The name and path of the application's executable file
- The name and path of a launcher application (optional)
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; }