main.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*****************************************************************************\
  19. 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
  20. *******************************************************************************
  21. File: main.cpp
  22. Programmer: Neal Kettler
  23. StartDate: Feb 6, 1998
  24. LastUpdate: Feb 10, 1998
  25. -------------------------------------------------------------------------------
  26. Launcher application for games/apps using the chat API. This should be
  27. run by the user and it will start the actual game executable. If a patch
  28. file has been downloaded the patch will be applied before starting the game.
  29. This does not download patches or do version checks, the game/app is responsible
  30. for that. This just applies patches that are in the correct location for the
  31. game. All patches should be in the "Patches" folder of the app.
  32. The launcher should have a config file (launcher.cfg) so it knows which apps
  33. should be checked for patches. The file should look like this:
  34. # comment
  35. # RUN = the game to launch
  36. RUN = . notepad.exe # directory and app name
  37. # RUN2 = the 2nd launcher if using one
  38. RUN2 = . wordpad.exe
  39. # FLAG = time in seconds of when to stop using 2nd launcher
  40. FLAG = 996778113
  41. #
  42. # Sku's to check for patches
  43. #
  44. SKU1 = 1100 SOFTWARE\Westwood\WOnline # skus and registry keys
  45. SKU2 = 1234 SOFTWARE\Westwood\FakeGame
  46. \*****************************************************************************/
  47. #include "dialog.h"
  48. #include "patch.h"
  49. #include "findpatch.h"
  50. #include "process.h"
  51. #include "wdebug.h"
  52. #include "monod.h"
  53. #include "filed.h"
  54. #include "configfile.h"
  55. #include <windows.h>
  56. #ifdef COPY_PROTECT
  57. #include "Protect.h"
  58. #endif
  59. #include <Debug\DebugPrint.h>
  60. #define UPDATE_RETVAL 123456789 // if a program returns this it means it wants to check for patches
  61. void CreatePrimaryWin(char *prefix);
  62. void myChdir(char *path);
  63. void RunGame(char *thePath, ConfigFile &config, Process &proc)
  64. {
  65. char patchFile[MAX_PATH];
  66. bool launchgame = true;
  67. // MDC 8/23/2001 Wait 3 seconds for the installer to release the mutex
  68. ///Sleep(3000);
  69. while (true)
  70. {
  71. int skuIndex;
  72. while ((skuIndex = Find_Patch(patchFile, MAX_PATH, config)) != 0)
  73. {
  74. Apply_Patch(patchFile, config, skuIndex);
  75. launchgame = true;
  76. }
  77. // launch the game if first pass, or found a patch
  78. if (launchgame)
  79. {
  80. // don't relaunch unless we find a patch (or checking for patches)
  81. launchgame = false;
  82. myChdir(thePath);
  83. #ifndef COPY_PROTECT
  84. Create_Process(proc);
  85. #else // COPY_PROTECT
  86. InitializeProtect();
  87. Create_Process(proc);
  88. SendProtectMessage(proc.hProcess, proc.dwThreadID);
  89. #endif // COPY_PROTECT
  90. DWORD exit_code;
  91. Wait_Process(proc, &exit_code);
  92. if (exit_code == UPDATE_RETVAL)
  93. {
  94. // They just want to check for patches
  95. launchgame = true;
  96. // Start patchgrabber
  97. Process patchgrab;
  98. strcpy(patchgrab.directory,proc.directory); // same dir as game
  99. strcpy(patchgrab.command,"patchget.dat"); // the program that grabs game patches
  100. strcpy(patchgrab.args,"");
  101. Create_Process(patchgrab);
  102. Wait_Process(patchgrab); // wait for completion
  103. }
  104. #ifdef COPY_PROTECT
  105. ShutdownProtect();
  106. #endif
  107. }
  108. else
  109. {
  110. Delete_Patches(config); // delete all patches
  111. break;
  112. }
  113. }
  114. }
  115. // The other launcher will handle itself. Just fire and forget.
  116. void RunLauncher(char *thePath, Process &proc)
  117. {
  118. myChdir(thePath);
  119. Create_Process(proc);
  120. }
  121. //
  122. // Called by WinMain
  123. //
  124. int main(int argc, char *argv[])
  125. {
  126. char patchFile[MAX_PATH];
  127. char cwd[MAX_PATH]; // save current directory before game start
  128. _getcwd(cwd, MAX_PATH);
  129. // Goto the folder where launcher is installed
  130. myChdir(argv[0]);
  131. // extract the program name from argv[0]. Change the extension to
  132. // .lcf (Launcher ConFig). This is the name of our config file.
  133. char configName[MAX_PATH + 3];
  134. strcpy(configName, argv[0]);
  135. char* extension = configName;
  136. char* tempptr;
  137. while ((tempptr = strchr(extension + 1, '.')))
  138. {
  139. extension = tempptr;
  140. }
  141. if (*extension == '.')
  142. {
  143. *extension = 0;
  144. }
  145. #ifdef DEBUG
  146. ///MonoD outputDevice;
  147. char debugFile[MAX_PATH + 3];
  148. strcpy(debugFile, configName);
  149. strcat(debugFile, ".txt");
  150. strcpy(debugLogName, strrchr(configName, '\\'));
  151. strcat(debugLogName, "Log");
  152. FileD outputDevice(debugFile, true);
  153. MsgManager::setAllStreams(&outputDevice);
  154. DBGMSG("Launcher initialized");
  155. #endif
  156. CreatePrimaryWin("generals");
  157. InitCommonControls();
  158. strcat(configName, ".lcf");
  159. DBGMSG("Config Name: "<<configName);
  160. ConfigFile config;
  161. FILE* in = fopen(configName, "r");
  162. if (in == NULL)
  163. {
  164. MessageBox(NULL,"You must run the game from its install directory.",
  165. "Launcher config file missing",MB_OK);
  166. exit(-1);
  167. }
  168. bit8 ok = config.readFile(in);
  169. fclose(in);
  170. if (ok == FALSE)
  171. {
  172. MessageBox(NULL,"File 'launcher.cfg' is corrupt","Error",MB_OK);
  173. exit(-1);
  174. }
  175. // Load process info
  176. Process proc;
  177. Read_Process_Info(config,proc);
  178. // Possible 2nd EXE
  179. Process proc2;
  180. int hasSecondEXE = Read_Process_Info(config,proc2,"RUN2");
  181. DBGMSG("Read process info");
  182. for (int i = 1; i < argc; i++)
  183. {
  184. strcat(proc.args, " ");
  185. strcat(proc.args, argv[i]);
  186. if (hasSecondEXE)
  187. {
  188. strcat(proc2.args, " ");
  189. strcat(proc2.args, argv[i]);
  190. }
  191. }
  192. DBGMSG("ARGS: "<<proc.args);
  193. // Just spawn the patchgrabber & apply any patches it downloads
  194. if ((argc >= 2) && (strcmp(argv[1], "GrabPatches") == 0))
  195. {
  196. // Start patchgrabber
  197. Process patchgrab;
  198. // same dir as game
  199. strcpy(patchgrab.directory, proc.directory);
  200. // the program that grabs game patches
  201. strcpy(patchgrab.command, "patchget.dat");
  202. strcpy(patchgrab.args, "");
  203. Create_Process(patchgrab);
  204. Wait_Process(patchgrab);
  205. // Apply any patches I find
  206. int skuIndex;
  207. while ((skuIndex = Find_Patch(patchFile, MAX_PATH, config)) != 0)
  208. {
  209. Apply_Patch(patchFile, config, skuIndex);
  210. }
  211. myChdir(cwd);
  212. return 0;
  213. }
  214. // Look for patch file(s) to apply
  215. bool launchgame = true;
  216. time_t cutoffTime = 0;
  217. if (hasSecondEXE)
  218. {
  219. Wstring timeStr;
  220. if (config.getString("FLAG", timeStr)!=FALSE)
  221. {
  222. cutoffTime = atoi(timeStr.get());
  223. }
  224. if (cutoffTime == 0)
  225. {
  226. // We didn't have the FLAG parameter; somebody's been hacking. No game for you! Bad hacker!
  227. DBGMSG("Saw cutoffTime of 0; real time is " << time(NULL));
  228. MessageBox(NULL,"File 'launcher.cfg' is corrupt","Error",MB_OK);
  229. exit(-1);
  230. }
  231. if (time(NULL) > cutoffTime)
  232. {
  233. // The future is now! Just run the game.
  234. RunGame(argv[0], config, proc);
  235. }
  236. else
  237. {
  238. // Its still early in the product's lifetime, so run the 2nd (SafeDisk'd) launcher.
  239. // We don't have to wait around since it'll do the entire talk to game, look for patches,
  240. // etc. deal.
  241. RunLauncher(argv[0], proc2);
  242. }
  243. }
  244. else
  245. {
  246. // We're the second (or only) launcher, so act normally
  247. RunGame(argv[0], config, proc);
  248. }
  249. myChdir(cwd);
  250. // Exit normally
  251. return 0;
  252. }
  253. //
  254. // Create a primary window
  255. //
  256. void CreatePrimaryWin(char *prefix)
  257. {
  258. char name[256];
  259. sprintf(name, "launcher_%s", prefix);
  260. DBGMSG("CreatePrimary: "<<name);
  261. /*
  262. ** set up and register window class
  263. */
  264. WNDCLASS wc;
  265. wc.style = CS_HREDRAW | CS_VREDRAW;
  266. wc.lpfnWndProc = DefWindowProc;
  267. wc.cbClsExtra = 0; // Don't need any extra class data
  268. wc.cbWndExtra = 0; // No extra win data
  269. wc.hInstance = Global_instance;
  270. wc.hIcon=LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_GENERALS));
  271. wc.hCursor = NULL; /////////LoadCursor( NULL, IDC_ARROW );
  272. wc.hbrBackground = NULL;
  273. wc.lpszMenuName = name;
  274. wc.lpszClassName = name;
  275. RegisterClass(&wc);
  276. /*
  277. ** create a window
  278. */
  279. HWND hwnd = CreateWindowEx(WS_EX_TOPMOST, name, name, WS_POPUP, 0, 0,
  280. GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
  281. NULL, NULL, Global_instance, NULL);
  282. if(!hwnd)
  283. {
  284. DBGMSG("Couldn't make window!");
  285. }
  286. else
  287. {
  288. DBGMSG("Window created!");
  289. }
  290. }
  291. //void DestroyPrimaryWin(void)
  292. //{
  293. // DestroyWindow(PrimaryWin);
  294. // UnregisterClass(classname);
  295. //}
  296. //
  297. // If given a file, it'll goto it's directory. If on a diff drive,
  298. // it'll go there.
  299. //
  300. void myChdir(char *path)
  301. {
  302. char drive[10];
  303. char dir[255];
  304. char file[255];
  305. char ext[64];
  306. char filepath[513];
  307. int abc;
  308. _splitpath( path, drive, dir, file, ext );
  309. _makepath ( filepath, drive, dir, NULL, NULL );
  310. if ( filepath[ strlen( filepath ) - 1 ] == '\\' )
  311. {
  312. filepath[ strlen( filepath ) - 1 ] = '\0';
  313. }
  314. abc = (unsigned)( toupper( filepath[0] ) - 'A' + 1 );
  315. if ( !_chdrive( abc ))
  316. {
  317. abc = chdir( filepath ); // Will fail with ending '\\'
  318. }
  319. // should be in proper folder now....
  320. }