| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*****************************************************************************\
- C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
- *******************************************************************************
- File: main.cpp
- Programmer: Neal Kettler
- StartDate: Feb 6, 1998
- LastUpdate: Feb 10, 1998
- -------------------------------------------------------------------------------
- Launcher application for games/apps using the chat API. This should be
- run by the user and it will start the actual game executable. If a patch
- file has been downloaded the patch will be applied before starting the game.
- This does not download patches or do version checks, the game/app is responsible
- for that. This just applies patches that are in the correct location for the
- game. All patches should be in the "Patches" folder of the app.
- The launcher should have a config file (launcher.cfg) so it knows which apps
- should be checked for patches. The file should look like this:
- # comment
- # RUN = the game to launch
- RUN = . notepad.exe # directory and app name
- # RUN2 = the 2nd launcher if using one
- RUN2 = . wordpad.exe
- # FLAG = time in seconds of when to stop using 2nd launcher
- FLAG = 996778113
- #
- # Sku's to check for patches
- #
- SKU1 = 1100 SOFTWARE\Westwood\WOnline # skus and registry keys
- SKU2 = 1234 SOFTWARE\Westwood\FakeGame
- \*****************************************************************************/
- #include "dialog.h"
- #include "patch.h"
- #include "findpatch.h"
- #include "process.h"
- #include "wdebug.h"
- #include "monod.h"
- #include "filed.h"
- #include "configfile.h"
- #include <windows.h>
- #ifdef COPY_PROTECT
- #include "Protect.h"
- #endif
- #include <Debug\DebugPrint.h>
- #define UPDATE_RETVAL 123456789 // if a program returns this it means it wants to check for patches
- void CreatePrimaryWin(char *prefix);
- void myChdir(char *path);
- void RunGame(char *thePath, ConfigFile &config, Process &proc)
- {
- char patchFile[MAX_PATH];
- bool launchgame = true;
- // MDC 8/23/2001 Wait 3 seconds for the installer to release the mutex
- ///Sleep(3000);
- while (true)
- {
- int skuIndex;
-
- while ((skuIndex = Find_Patch(patchFile, MAX_PATH, config)) != 0)
- {
- Apply_Patch(patchFile, config, skuIndex);
- launchgame = true;
- }
-
- // launch the game if first pass, or found a patch
- if (launchgame)
- {
- // don't relaunch unless we find a patch (or checking for patches)
- launchgame = false;
- myChdir(thePath);
-
- #ifndef COPY_PROTECT
- Create_Process(proc);
- #else // COPY_PROTECT
- InitializeProtect();
- Create_Process(proc);
- SendProtectMessage(proc.hProcess, proc.dwThreadID);
-
- #endif // COPY_PROTECT
-
- DWORD exit_code;
- Wait_Process(proc, &exit_code);
-
- if (exit_code == UPDATE_RETVAL)
- {
- // They just want to check for patches
- launchgame = true;
-
- // Start patchgrabber
- Process patchgrab;
- strcpy(patchgrab.directory,proc.directory); // same dir as game
- strcpy(patchgrab.command,"patchget.dat"); // the program that grabs game patches
- strcpy(patchgrab.args,"");
- Create_Process(patchgrab);
- Wait_Process(patchgrab); // wait for completion
- }
-
- #ifdef COPY_PROTECT
- ShutdownProtect();
- #endif
- }
- else
- {
- Delete_Patches(config); // delete all patches
- break;
- }
- }
- }
- // The other launcher will handle itself. Just fire and forget.
- void RunLauncher(char *thePath, Process &proc)
- {
- myChdir(thePath);
- Create_Process(proc);
- }
- //
- // Called by WinMain
- //
- int main(int argc, char *argv[])
- {
- char patchFile[MAX_PATH];
- char cwd[MAX_PATH]; // save current directory before game start
- _getcwd(cwd, MAX_PATH);
-
- // Goto the folder where launcher is installed
- myChdir(argv[0]);
-
- // extract the program name from argv[0]. Change the extension to
- // .lcf (Launcher ConFig). This is the name of our config file.
- char configName[MAX_PATH + 3];
- strcpy(configName, argv[0]);
- char* extension = configName;
- char* tempptr;
-
- while ((tempptr = strchr(extension + 1, '.')))
- {
- extension = tempptr;
- }
-
- if (*extension == '.')
- {
- *extension = 0;
- }
-
- #ifdef DEBUG
- ///MonoD outputDevice;
- char debugFile[MAX_PATH + 3];
- strcpy(debugFile, configName);
- strcat(debugFile, ".txt");
- strcpy(debugLogName, strrchr(configName, '\\'));
- strcat(debugLogName, "Log");
- FileD outputDevice(debugFile, true);
- MsgManager::setAllStreams(&outputDevice);
- DBGMSG("Launcher initialized");
- #endif
- CreatePrimaryWin("generals");
- InitCommonControls();
- strcat(configName, ".lcf");
-
- DBGMSG("Config Name: "<<configName);
-
- ConfigFile config;
- FILE* in = fopen(configName, "r");
-
- if (in == NULL)
- {
- MessageBox(NULL,"You must run the game from its install directory.",
- "Launcher config file missing",MB_OK);
- exit(-1);
- }
-
- bit8 ok = config.readFile(in);
- fclose(in);
-
- if (ok == FALSE)
- {
- MessageBox(NULL,"File 'launcher.cfg' is corrupt","Error",MB_OK);
- exit(-1);
- }
-
- // Load process info
- Process proc;
- Read_Process_Info(config,proc);
-
- // Possible 2nd EXE
- Process proc2;
- int hasSecondEXE = Read_Process_Info(config,proc2,"RUN2");
-
- DBGMSG("Read process info");
-
- for (int i = 1; i < argc; i++)
- {
- strcat(proc.args, " ");
- strcat(proc.args, argv[i]);
-
- if (hasSecondEXE)
- {
- strcat(proc2.args, " ");
- strcat(proc2.args, argv[i]);
- }
- }
-
- DBGMSG("ARGS: "<<proc.args);
- // Just spawn the patchgrabber & apply any patches it downloads
- if ((argc >= 2) && (strcmp(argv[1], "GrabPatches") == 0))
- {
- // Start patchgrabber
- Process patchgrab;
- // same dir as game
- strcpy(patchgrab.directory, proc.directory);
-
- // the program that grabs game patches
- strcpy(patchgrab.command, "patchget.dat");
- strcpy(patchgrab.args, "");
-
- Create_Process(patchgrab);
- Wait_Process(patchgrab);
-
- // Apply any patches I find
- int skuIndex;
-
- while ((skuIndex = Find_Patch(patchFile, MAX_PATH, config)) != 0)
- {
- Apply_Patch(patchFile, config, skuIndex);
- }
-
- myChdir(cwd);
- return 0;
- }
-
- // Look for patch file(s) to apply
- bool launchgame = true;
- time_t cutoffTime = 0;
- if (hasSecondEXE)
- {
- Wstring timeStr;
- if (config.getString("FLAG", timeStr)!=FALSE)
- {
- cutoffTime = atoi(timeStr.get());
- }
-
- if (cutoffTime == 0)
- {
- // We didn't have the FLAG parameter; somebody's been hacking. No game for you! Bad hacker!
- DBGMSG("Saw cutoffTime of 0; real time is " << time(NULL));
- MessageBox(NULL,"File 'launcher.cfg' is corrupt","Error",MB_OK);
- exit(-1);
- }
- if (time(NULL) > cutoffTime)
- {
- // The future is now! Just run the game.
- RunGame(argv[0], config, proc);
- }
- else
- {
- // Its still early in the product's lifetime, so run the 2nd (SafeDisk'd) launcher.
- // We don't have to wait around since it'll do the entire talk to game, look for patches,
- // etc. deal.
- RunLauncher(argv[0], proc2);
- }
- }
- else
- {
- // We're the second (or only) launcher, so act normally
- RunGame(argv[0], config, proc);
- }
- myChdir(cwd);
-
- // Exit normally
- return 0;
- }
- //
- // Create a primary window
- //
- void CreatePrimaryWin(char *prefix)
- {
- char name[256];
- sprintf(name, "launcher_%s", prefix);
-
- DBGMSG("CreatePrimary: "<<name);
-
- /*
- ** set up and register window class
- */
- WNDCLASS wc;
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = DefWindowProc;
- wc.cbClsExtra = 0; // Don't need any extra class data
- wc.cbWndExtra = 0; // No extra win data
- wc.hInstance = Global_instance;
- wc.hIcon=LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_GENERALS));
- wc.hCursor = NULL; /////////LoadCursor( NULL, IDC_ARROW );
- wc.hbrBackground = NULL;
- wc.lpszMenuName = name;
- wc.lpszClassName = name;
- RegisterClass(&wc);
-
- /*
- ** create a window
- */
- HWND hwnd = CreateWindowEx(WS_EX_TOPMOST, name, name, WS_POPUP, 0, 0,
- GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
- NULL, NULL, Global_instance, NULL);
-
- if(!hwnd)
- {
- DBGMSG("Couldn't make window!");
- }
- else
- {
- DBGMSG("Window created!");
- }
- }
- //void DestroyPrimaryWin(void)
- //{
- // DestroyWindow(PrimaryWin);
- // UnregisterClass(classname);
- //}
- //
- // If given a file, it'll goto it's directory. If on a diff drive,
- // it'll go there.
- //
- void myChdir(char *path)
- {
- char drive[10];
- char dir[255];
- char file[255];
- char ext[64];
- char filepath[513];
- int abc;
-
- _splitpath( path, drive, dir, file, ext );
- _makepath ( filepath, drive, dir, NULL, NULL );
-
- if ( filepath[ strlen( filepath ) - 1 ] == '\\' )
- {
- filepath[ strlen( filepath ) - 1 ] = '\0';
- }
- abc = (unsigned)( toupper( filepath[0] ) - 'A' + 1 );
- if ( !_chdrive( abc ))
- {
- abc = chdir( filepath ); // Will fail with ending '\\'
- }
- // should be in proper folder now....
- }
|