Microsoft DirectPlay: Changes for Supporting Ripple Launch

Microsoft Corporation

October 1999

Summary: This article explains the changes made in Microsoft® DirectPlay® version 7.0 that allow the DirecPlayLobby to support a number of ripple launch scenarios. (7 printed pages)

Introduction

New changes made in Microsoft® DirectPlay® version 7.0 allow the DirecPlayLobby to support a number of ripple launch scenarios. In order to support these ripple launch scenarios, a few modifications have been made to the DirectPlayLobby. DirectPlayLobby supports numerous interprocess communication (IPC) facilities. The IPC connections were established using the process ID of the application being launched. This was accomplished by generated shared object names, which included the process ID of the application being launched in the shared object name. See Figure 1.

Figure 1. Normal Lobby IPC Setup

A ripple launch is where one application is required to launch another application. In this scenario, trying to establish the IPC link between the DirectPlayLobby in the Lobby Client AND the DirectPlayLobby in the lobbied application would not work. The reason is because the Lobby Client would try to establish communication on shared objects using the launcher process ID, whereas the application that was launched by the ripple launcher would try to establish communication on shared objects using its process ID. See Figure 2.

Figure 2. Unsuccessful Lobby IPC Launch

In order to alleviate this problem when using a launcher application, a command line switch is passed to the launched application informing it of the identity of the IPC objects. See Figure 3.

Figure 3. Successful Lobby IPC Launch

These changes to DirectPlayLobby will be completely transparent to existing applications or non-protected ones. The original functionality will operate the same. For those games relying on setup to create the Lobby registry entries, a new value will need to be added to the DirectPlayLobby game key, "Launcher" with the name of the launching exe (with one example, it's the game exe). The game exe name (value "File") is changed to gameexename.icd (where gameexename is the name of the original exe for the game, with an .icd extension instead of an .exe extension).

This alleviates the problems that occur in a ripple launch scenario. This design puts numerous requirements on the ripple launching application and the registration of the game for lobbying. Details follow.

Changes to IDirectPlayLobby::RegisterApplication

RegisterApplication now accepts both LPDPAPPLICATIONDESC and LPDPAPPLICATIONDESC2 in the lpAppDesc field.

HRESULT RegisterApplication(
   DWORD dwFlags,
   LPVOID lpAppDesc
);

You will notice that the DPAPPLICATIONDESC2 structure has an additional field for specifying lpszAppLauncherName. This is the name of the binary that should be launched instead of the application. The application launcher should reside in the same directory as the actual binary. The application name still needs to be provided and is used in the case of WaitForConnectionSettings to find the running application on the system.

typedef struct {
   DWORD   dwSize; 
   DWORD   dwFlags; 
   union {
      LPSTR      lpszApplicationNameA;
      LPWSTR   lpszApplicationName;
   }
   GUID   guidApplication;
   union {
      LPSTR      lpszFilenameA;
      LPWSTR   lpszFilename;
   }
   union {
      LPSTR      lpszCommandLineA;
      LPWSTR   lpszCommandLine;
   }
   union {
      LPSTR      lpszPathA;
      LPWSTR   lpszPath;
   }
   union {
      LPSTR      lpszCurrentDirectoryA;
      LPWSTR   lpszCurrentDirectory;
   }
   LPSTR      lpszDescriptionA;
   LPWSTR   lpszDescriptionW;
} DPAPPLICATIONDESC, FAR *LPDPAPPLICATIONDESC;

typedef struct DPAPPLICATIONDESC2
{
   DWORD         dwSize;
   DWORD         dwFlags;
   union
   {
         LPSTR         lpszApplicationNameA;
         LPWSTR      lpszApplicationName;
   };
   GUID         guidApplication;
   union
   {
         LPSTR         lpszFilenameA;
         LPWSTR      lpszFilename;
   };
   union
   {
         LPSTR         lpszCommandLineA;
         LPWSTR      lpszCommandLine;
   };
   union
   {
         LPSTR         lpszPathA;
         LPWSTR      lpszPath;
   };
   union
   {
         LPSTR         lpszCurrentDirectoryA;
         LPWSTR      lpszCurrentDirectory;
   };
   LPSTR         lpszDescriptionA;
   LPWSTR      lpszDescriptionW;
   union
   {
      LPSTR         lpszAppLauncherNameA;
      LPWSTR      lpszAppLauncherName;
   };
} DPAPPLICATIONDESC2, *LPDPAPPLICATIONDESC2;

Sample Showing Change to Registering an Application

Before

DPAPPLICATIONDESC   dpad;

...
dpad.dwSize = sizeof (DPAPPLICATIONDESC);
dpad.dwFlags = 0;
dpad.lpszApplicationNameA= "MyApp";
dpad.guidApplication = {12345678-...};
dpad.lpszFilenameA= "myapp.exe";
dpad.lpszCommandLineA= "/lobbied";
dpad.lpszPathA= "C:\\games";
dpad.lpszCurrentDirectoryA= "C:\\games";
dpad.lpszDescriptionA= "My Application";
dpad.lpszDescriptionW= L"My Application";

hr = lpDPLobby3A->RegisterApplication(0, &dpad);
...

"C:\games\myapp.exe /lobbied" will be executed when RunApplication is called with the {12345678-...} GUID.

After

DPAPPLICATIONDESC2   dpad2;

...
dpad2.dwSize = sizeof (DPAPPLICATIONDESC2);
dpad2.dwFlags = 0;
dpad2.lpszApplicationNameA= "MyApp";
dpad2.guidApplication = {12345678-...};
dpad2.lpszFilenameA= "myapp.exe";
dpad2.lpszCommandLineA= "/lobbied";
dpad2.lpszPathA= "C:\\games";
dpad2.lpszCurrentDirectoryA= "C:\\games";
dpad2.lpszDescriptionA= "My Application";
dpad2.lpszDescriptionW= L"My Application";
dpad2.lpszAppLauncherNameA= "launcher.exe";

hr = lpDPLobby3A->RegisterApplication(0, &dpad2);
...

"C:\games\launcher.exe /dplay_ipc_guid:{12345678-...} /lobbied" will be executed when RunApplication is called with the {12345678-...} GUID. LAUNCHER.EXE must pass all command line parameters to MYAPP.EXE.

Requirements for a Launcher Application

A launcher application must pass on the command line parameters with which it is provided to the application being launched. The launcher application must reside in the same directory as the application being launched.

Requirements for Applications Launched through a Launcher

An application that wishes to be launchable through a launcher application should silently ignore any command line parameters it does not understand. Such an application should always call GetConnectionSettings at least once before using WaitForConnectionSettings.

Sample Ripple Launch Application

//
// ripple.c : example ripple launcher.  Win32 Console Application
//

#include <windows.h>
#include "stdio.h"

int main(int argc, char* argv[])
{
   PROCESS_INFORMATION ProcInfo;
   STARTUPINFO StartupInfo;
   BOOL bCreated;

   LPTSTR lpCommandLine;

   printf("Launcher application\n");

   lpCommandLine = GetCommandLineA();

   // Strip EXE name from command line, pass rest to ripple launched app.
   while(*lpCommandLine && *lpCommandLine!= ' ') lpCommandLine++;
   
   printf("passing command line: %s\n",lpCommandLine);

   memset(&StartupInfo,0,sizeof(StartupInfo));
   StartupInfo.cb = sizeof(StartupInfo);
   
   bCreated=CreateProcessA(
      "duel.exe",      // the program we are ripple launching.
      lpCommandLine,
      NULL,
      NULL,
      TRUE,
      0,
      NULL,
      NULL,
      &StartupInfo,
      &ProcInfo);


   if(bCreated){
      printf("Waiting for application to exit\n");
      WaitForSingleObject(ProcInfo.hThread, INFINITE);
   } else {
      printf("Failed to create process\n");
   }

   printf("launcher application has left the building...\n");

   return 0;
}