Reloader.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*-------------------------------------------------------------------------
  2. * Reloader.cpp
  3. *-------------------------------------------------------------------------
  4. *
  5. * This app does this:
  6. *
  7. * 1) Waits for Allegiance to exit.
  8. * 2) Looks in the regristy for ArtPath.
  9. * 3) Moves Art Files from Temp folder to Art folder.
  10. * Moves Special files (Allegiance.exe and Allegiance.pdb) to current folder. (If they
  11. * exist in temp folder.)
  12. * 4) Reloads Allegiance.exe with the command-line specified to this app.
  13. *
  14. *
  15. * The command-line has two parts. The first part is a number specifying the Process ID of
  16. * the currently running Allegiance.exe. The second part is the orignial command-line sent
  17. * to Allegiance.exe which is re-fed to the newly spawned Allegiance.exe.
  18. */
  19. #include "pch.h"
  20. #include "..\Zlib\FTPSession.h"
  21. #include "..\Clintlib\AutoDownload.h" // don't included in pch because build process doesn't realize
  22. // when AutoDownload.h changes, and since this project
  23. // only has one cpp file, a pch doesn't help anyway (except
  24. // that our build process requires it).
  25. /*-------------------------------------------------------------------------
  26. * GetArtPath()
  27. *-------------------------------------------------------------------------
  28. * Returns:
  29. * Art Path of client as specified in registry
  30. */
  31. char * GetArtPath()
  32. {
  33. static char pathStr[MAX_PATH + 16];
  34. HKEY hKey;
  35. DWORD dwType;
  36. DWORD cbValue = MAX_PATH;
  37. BOOL bResult = FALSE;
  38. if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, ALLEGIANCE_REGISTRY_KEY_ROOT, 0, KEY_READ, &hKey))
  39. {
  40. // Get the art path from the registry
  41. bResult = (ERROR_SUCCESS == ::RegQueryValueEx(hKey, "ArtPath", NULL, &dwType, (unsigned char*)&pathStr, &cbValue));
  42. ::RegCloseKey(hKey);
  43. int const cLen = strlen(pathStr);
  44. // convert to \ format
  45. for (int i = 0; i < cLen; ++i)
  46. if(pathStr[i] == '/')
  47. pathStr[i] = '\\';
  48. // assure last char has end
  49. if (cLen == 0 || pathStr[cLen-1] != '\\')
  50. strcat(pathStr, "\\");
  51. }
  52. if (!bResult)
  53. {
  54. // ::MessageBox(NULL, "Error reading ArtPath from registry; assuming .\\Artwork\\ if this isn't right, you might need to reinstall.", "AutoUpdate Reloader Error", MB_ICONEXCLAMATION);
  55. strcpy(pathStr, ".\\Artwork\\");
  56. }
  57. return pathStr;
  58. }
  59. /*-------------------------------------------------------------------------
  60. * DisplayErrorMsg()
  61. *-------------------------------------------------------------------------
  62. * Purpose:
  63. * report an error
  64. */
  65. void DisplayErrorMsg(char *szError)
  66. {
  67. int nErrorCode = GetLastError();
  68. // Give time for Allegiance to minimize
  69. ::Sleep(1000);
  70. char sz[100];
  71. sprintf(sz, "Error occured during auto update (Code = %d)", nErrorCode);
  72. ::MessageBox(NULL, szError, sz, MB_ICONEXCLAMATION);
  73. }
  74. class CAutoDownloadSink : public IAutoUpdateSink
  75. {
  76. /*-------------------------------------------------------------------------
  77. * OnMoveError()
  78. *-------------------------------------------------------------------------
  79. * Purpose:
  80. * Handles MoveFiles() Errors. Give user option to try again.
  81. *
  82. * Returns: true if the user wants to try again.
  83. */
  84. bool OnMoveError(char *szErrorMessage)
  85. {
  86. static int cCalled = 0;
  87. //
  88. // The first few time this function is called, we ignore it and keep
  89. // trying to move the files. It's possbile that Allegiance.exe isn't
  90. // done exiting and has some files open.
  91. //
  92. if (++cCalled > 25) // 25 secs
  93. {
  94. //
  95. // Give User the option to wait longer
  96. //
  97. int nErrorCode = GetLastError();
  98. // Give time for Allegiance to minimize
  99. ::Sleep(1000);
  100. char szTitle[100];
  101. sprintf(szTitle, "Error occured during auto update (Code = %d)", nErrorCode);
  102. char szMsg[500];
  103. sprintf(szMsg, "%s\r\n\r\n\r\n\r\nDo you wish to retry moving the files?", szErrorMessage);
  104. if (::MessageBox(NULL, szMsg, szTitle, MB_YESNO) == IDYES)
  105. return true;
  106. else
  107. return false;
  108. }
  109. else
  110. {
  111. Sleep(1000); // wait a bit for Allegiance.exe's files to close and try again.
  112. return true; // signal to try again
  113. }
  114. }
  115. } g_AutoDownloadSink;
  116. // returns true only if file exists
  117. bool Exists(const char * szFileName)
  118. {
  119. HANDLE hFile = CreateFile(szFileName,
  120. 0,
  121. FILE_SHARE_READ,
  122. NULL,
  123. OPEN_EXISTING,
  124. FILE_ATTRIBUTE_NORMAL,
  125. NULL);
  126. if (hFile == INVALID_HANDLE_VALUE)
  127. return false;
  128. ::CloseHandle(hFile);
  129. return true;
  130. }
  131. bool GetFileTime(char * szFileName, LPFILETIME pft)
  132. {
  133. HANDLE hFile = CreateFile(szFileName,
  134. 0,
  135. FILE_SHARE_READ,
  136. NULL,
  137. OPEN_EXISTING,
  138. FILE_ATTRIBUTE_NORMAL,
  139. NULL);
  140. if (hFile == INVALID_HANDLE_VALUE)
  141. return false;
  142. GetFileTime(hFile, NULL, NULL, pft);
  143. CloseHandle(hFile);
  144. return true;
  145. }
  146. //
  147. // Rename mangled name to correct name
  148. //
  149. void RenameMangledFile(char * szMangled, char * szCorrect)
  150. {
  151. if (Exists(szMangled))
  152. {
  153. // force another autoupdate to ensure version is correct
  154. DeleteFile("Filelist.txt");
  155. DeleteFile("AutoUpdate\\Filelist.txt");
  156. char szBuffer[MAX_PATH*2 + 20];
  157. if (Exists(szCorrect))
  158. {
  159. FILETIME ftMangled;
  160. FILETIME ftCorrect;
  161. if (!GetFileTime(szMangled, &ftMangled) ||
  162. !GetFileTime(szCorrect, &ftCorrect))
  163. {
  164. sprintf(szBuffer, "Unable to examine at least one of these files: %s, %s. Reboot your computer and try again.", szMangled, szCorrect);
  165. DisplayErrorMsg(szBuffer);
  166. ExitProcess(-1);
  167. return;
  168. }
  169. if (CompareFileTime(&ftCorrect, &ftMangled) > 0) // if existing correct file is newer; keep it
  170. {
  171. OutputDebugString("\nDeleting old file with mangled name ");
  172. OutputDebugString(szMangled);
  173. DeleteFile(szMangled);
  174. return;
  175. }
  176. OutputDebugString("\nDeleting old file with correct name ");
  177. OutputDebugString(szCorrect);
  178. if (!DeleteFile(szCorrect))
  179. {
  180. ::Sleep(2000);
  181. if (!DeleteFile(szCorrect))
  182. {
  183. ::Sleep(10000);
  184. DeleteFile(szCorrect);
  185. }
  186. }
  187. }
  188. sprintf(szBuffer, "\nRenaming %s to %s\n", szMangled, szCorrect);
  189. OutputDebugString(szBuffer);
  190. if (!MoveFile(szMangled, szCorrect))
  191. {
  192. sprintf(szBuffer, "Unable to rename %s to %s. Reboot your computer and run Allegiance to try again.", szMangled, szCorrect);
  193. DisplayErrorMsg(szBuffer);
  194. ExitProcess(-1);
  195. }
  196. }
  197. }
  198. /*-------------------------------------------------------------------------
  199. * RenameMangledFiles()
  200. *-------------------------------------------------------------------------
  201. *
  202. * Rename files with mangled filenames as part of the PC-Gamer/Beta1 fix.
  203. *
  204. */
  205. void RenameMangledFiles()
  206. {
  207. for (int i = 0; i < g_cEXEFiles; ++i)
  208. {
  209. char szMangled[MAX_PATH];
  210. char * szCorrect = CAutoDownloadUtil::GetEXEFileName(i);
  211. // we can only handle string of at least 8 characters
  212. if (strlen(szCorrect) < 8)
  213. continue;
  214. //
  215. // create the mangled counterpart to GetEXEFileName(i)
  216. //
  217. strcpy(szMangled, szCorrect);
  218. strcpy(szMangled+8, szCorrect);
  219. RenameMangledFile(szMangled, szCorrect);
  220. }
  221. //
  222. // Now do special files
  223. //
  224. RenameMangledFile("AllegianAllegiance.exe", "Allegiance.exe");
  225. RenameMangledFile("AllegianAllegianceDebug.exe", "Allegiance.exe");
  226. RenameMangledFile("AllegianAllegianceRetail.exe", "Allegiance.exe");
  227. RenameMangledFile("AllegianAllegianceTest.exe", "Allegiance.exe");
  228. RenameMangledFile("AllegianAllegiance.pdb", "Allegiance.pdb");
  229. RenameMangledFile("AllegianAllegianceDebug.pdb", "Allegiance.pdb");
  230. RenameMangledFile("AllegianAllegianceRetail.pdb", "Allegiance.pdb");
  231. RenameMangledFile("AllegianAllegianceTest.pdb", "Allegiance.pdb");
  232. RenameMangledFile("AllegianAllegiance.sym", "Allegiance.sym");
  233. RenameMangledFile("AllegianAllegianceDebug.sym", "Allegiance.sym");
  234. RenameMangledFile("AllegianAllegianceRetail.sym", "Allegiance.sym");
  235. RenameMangledFile("AllegianAllegianceTest.sym", "Allegiance.sym");
  236. RenameMangledFile("AllegianAllegiance.map", "Allegiance.map");
  237. RenameMangledFile("AllegianAllegianceDebug.map", "Allegiance.map");
  238. RenameMangledFile("AllegianAllegianceRetail.map", "Allegiance.map");
  239. RenameMangledFile("AllegianAllegianceTest.map", "Allegiance.map");
  240. }
  241. /*-------------------------------------------------------------------------
  242. * WinMain()
  243. *-------------------------------------------------------------------------
  244. *
  245. * See top of file for description.
  246. *
  247. */
  248. int APIENTRY WinMain(HINSTANCE hInstance,
  249. HINSTANCE hPrevInstance,
  250. LPSTR lpCmdLine,
  251. int nCmdShow)
  252. {
  253. // make sure this is commmented out
  254. // DebugBreak();
  255. RenameMangledFiles(); // PC-Gamer/Beta 1 build fix
  256. char *pCmdLine = lpCmdLine;
  257. DWORD dwProcessID = atol(pCmdLine);
  258. HANDLE hProcess;
  259. if(dwProcessID == 0)
  260. {
  261. DisplayErrorMsg("Allegiance.exe gave Reloader.exe an invalid command-line.");
  262. return 1;
  263. }
  264. char * szArtPath = GetArtPath();
  265. hProcess = ::OpenProcess(PROCESS_TERMINATE, false, dwProcessID);
  266. if (hProcess == NULL)
  267. {
  268. if (GetLastError() != ERROR_INVALID_PARAMETER) // returns this if Process of this ID doesn't exist
  269. {
  270. DisplayErrorMsg("Couldn't Access Allegiance.exe Process. Press OK to try continue update anyway.");
  271. }
  272. else
  273. {
  274. //
  275. // We are assuming that Allegiance is already killed itself. So everything is
  276. // okay and just fall through.
  277. //
  278. }
  279. }
  280. else
  281. {
  282. //
  283. // Give Allegiance some time to exit
  284. //
  285. int counter = 0;
  286. while (hProcess && counter++ < 40) // wait about 4 seconds (don't make too high!)
  287. {
  288. Sleep(100);
  289. ::CloseHandle(hProcess);
  290. // Note: win98 returns a non NULL handle even if the process is dead
  291. hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);
  292. }
  293. if (hProcess)
  294. {
  295. //
  296. // Took too long to shut down!
  297. // Let's terminate Allegiance (to be sure it shuts down)
  298. //
  299. if (::TerminateProcess(hProcess, 0) == 0)
  300. {
  301. DisplayErrorMsg("Couldn't Terminate Allegiance. Press OK to try continue update anyway.");
  302. }
  303. ::Sleep(1000); // give some time for terminatation
  304. }
  305. }
  306. if(hProcess)
  307. ::CloseHandle(hProcess);
  308. //
  309. // At this point Allegiance is dead.
  310. //
  311. ::Sleep(1000); // we wait a little more to help ensure Allegiance is completely dead.
  312. if (!CAutoDownloadUtil::MoveFiles("AutoUpdate\\", szArtPath, false, NULL, false, NULL, &g_AutoDownloadSink))
  313. {
  314. DisplayErrorMsg("Couldn't move at least one of the downloaded files. Reboot and try again. As a last resort, you may need to reinstall.");
  315. return 3;
  316. }
  317. //
  318. // Reload Allegiance
  319. //
  320. if (pCmdLine && pCmdLine[0] != 0)
  321. pCmdLine = strchr(pCmdLine+1, ' '); // fast forward a bit
  322. bool bLaunchMinimized = false;
  323. if (pCmdLine && pCmdLine[0] != 0)
  324. {
  325. if (_strnicmp(pCmdLine, "-Minimized", 10))
  326. {
  327. bLaunchMinimized = true;
  328. }
  329. pCmdLine = strchr(pCmdLine+1, ' '); // fast forward a bit
  330. }
  331. char szNewCommandLine[512] = {""};
  332. if (pCmdLine && pCmdLine[0] != 0)
  333. strncpy(szNewCommandLine, pCmdLine, 500); // re-feed the original command-line back into Allegiance.exe
  334. strcat(szNewCommandLine, " -reloaded");
  335. if((int)ShellExecute(0,
  336. "Open",
  337. "Allegiance.exe",
  338. szNewCommandLine,
  339. NULL,
  340. bLaunchMinimized ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL
  341. ) <= 32)
  342. {
  343. DisplayErrorMsg("Couldn't automatically restart Allegiance. Please manually restart the game.");
  344. return 5;
  345. }
  346. return 0;
  347. }