MORE INFORMATION
If you use a versions of DPlay earlier than 6.1a (released
4/99) to run a game created with Ripple Raunch capability, you may be unable to
connect to the game online or lose connections that you did make because the
ripple launcher program's encryption scheme breaks DPlay's handshaking
protocol. DPlay 6.1a (or later) is updated to allow your game (or the program
you are developing) to use this encryption technology with DPlay. The original
functionality of DPlay remains the same and is backwards compatible with
earlier versions.
The most significant change to DPlay 6.1a for
Ripple Launch support involves the processing of Interprocess Communication
(IPC) facilities with connections in the DirectPlayLobby. Before DPlay 6.1a, an
IPC connection was established by including the process ID of the program being
started in the shared IPC object name. Each program has a static Globally
Unique Identifier (GUID) embedded and installed with the program and a dynamic
process ID automatically issued with each running instance of the program. With
DPlay 6.1a, the IPC connection is established when the ripple launcher program
uses its own process identifier to send a command-line switch to the program to
inform it of the identify of the IPC objects. In a ripple launch scenario, each
program can also be issued a dynamic GUID along with the dynamic process
identifier.
To implement a ripple launch scenario for those games
relying on Setup to create the Lobby registry entries, changes must be made to
the DirectPlayLobby registry keys "Launcher" and "File." The Launcher registry
key must be the name of the path of the executable file being started and File
is the name of the original executable file for the game with an .icd extension
instead of an .exe extension (for example,
gameexename.icd).
These registry changes
put numerous requirements on the ripple launching program and the registration
of the game for lobbying. These details are as follows:
Changes to DirectPlayLobby in RegisterApplication
RegisterApplication now accepts both LPDPAPPLICATIONDESC and
LPDPAPPLICATIONDESC2 in the lpAppDesc field.
HRESULT RegisterApplication(
DWORD dwFlags,
LPVOID lpAppDesc
);
You may notice that the DPAPPLICATIONDESC2 structure has an additional
field for specifying lpszAppLauncherName. This is the name of the binary file
to be started, instead of the program. The ripple launcher program should
reside in the same directory as the actual binary file. The program name still
needs to be provided and is used in the case of WaitForConnectionSettings in
order to find the running program 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;
type def 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 Code Showing Class Registration Change
-
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" is 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" is run
when RunApplication is called with the {12345678-...} GUID. The ripple launch
program must pass all command-line parameters to
Myapp.exe.
Requirements for a Program Started with Launcher.exe
The ripple launch program must pass any command-line parameters
to the program being started. The launcher.exe program must reside in the same
folder as the program being started.
Requirements for Programs Started with Launcher.exe
A program started with the ripple launch program should silently
ignore any command-line parameters it does not understand. Such a program
should always call GetConnectionSettings at least once before using
WaitForConnectionSettings.
Sample Ripple Launch Program
//
// 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;
}