Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
patch.cpp
Go to the documentation of this file.
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/*****************************************************************************\
20 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
21*******************************************************************************
22 File: patch.cpp
23 Programmer: Neal Kettler
24
25 StartDate: Feb 6, 1998
26 LastUpdate: Feb 10, 1998
27-------------------------------------------------------------------------------
28
29This is where all the code is for applying various types of patches.
30
31\*****************************************************************************/
32
33
34#include "patch.h"
35#include <shellapi.h>
36#include <direct.h>
37
38
39//
40// For the text box showing patch info
41//
42BOOL CALLBACK Update_Info_Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
43{
44
45 static int unselectText=0;
46
47 switch(iMsg)
48 {
49 case WM_INITDIALOG:
50 {
51 FILE *in = fopen("launcher.txt","r");
52 if (in==NULL)
53 {
54 EndDialog(hwnd,-1);
55 return(1);
56 }
57
58 char line[270];
59 int lastsel=0;
60 char *cptr=NULL;
61 while(fgets(line,255,in))
62 {
63 //Get rid of any trailing junk
64 while(1)
65 {
66 if (strlen(line)<1)
67 break;
68 cptr=line+(strlen(line))-1;
69 if ((*cptr=='\r')||(*cptr=='\n'))
70 *cptr=0;
71 else
72 break;
73 }
74 // ...and add back the gunk that windows likes
75 strcat(line,"\r\r\n");
76
77 SendDlgItemMessage(hwnd, IDC_TEXT, EM_SETSEL, (WPARAM)lastsel, (LPARAM)lastsel );
78 SendDlgItemMessage(hwnd, IDC_TEXT, EM_REPLACESEL, 0, (LPARAM)(line) );
79 SendDlgItemMessage(hwnd, IDC_TEXT, EM_GETSEL, (WPARAM)NULL, (LPARAM)&lastsel );
80 }
81 unselectText=1;
82 fclose(in);
83
84 return(1); // 1 means windows handles focus issues
85 }
86 break;
87
88 case WM_PAINT:
89 if (unselectText)
90 SendDlgItemMessage(hwnd, IDC_TEXT, EM_SETSEL, -1, 0);
91 unselectText=0;
92 return(0);
93 break;
94
95
96 case WM_COMMAND:
97 switch(wParam) {
98 case IDOK:
99 {
100 EndDialog(hwnd,0);
101 return(1);
102 }
103 default:
104 break;
105 }
106 default:
107 break;
108 case WM_CLOSE:
109 EndDialog(hwnd,0);
110 return(1);
111 break;
112 }
113 return(FALSE);
114}
115
116
117
118
119
120
121
122// Restart the computer for certain types of patches
123void Shutdown_Computer_Now(void);
124
125
126__declspec(dllexport) LPVOID CALLBACK PatchCallBack(UINT ID, LPVOID Param);
127
128typedef LPVOID (CALLBACK* PATCHCALLBACK)(UINT, LPVOID);
129typedef UINT (CALLBACK *PATCHFUNC)( LPSTR, PATCHCALLBACK, BOOL);
130
131//
132// Apply any type of patch. Filename in patchfile. Product base registry
133// (eg: "SOFTWARE\Westwood\Red Alert") should be in the config file as
134// SKUX SKU base reg dir where X = index
135//
136void Apply_Patch(char *patchfile,ConfigFile &config,int skuIndex)
137{
138 DBGMSG("PATCHFILE : "<<patchfile);
139 char cwdbuf[256];
140 _getcwd(cwdbuf,255);
141 DBGMSG("CWD : "<<cwdbuf);
142
143 //
144 // If patch is a .exe type patch
145 //
146 if (strcasecmp(patchfile+strlen(patchfile)-strlen(".exe"),".exe")==0)
147 {
148 // Set this as a run once service thing
149 HKEY regKey;
150 LONG regRetval;
151 DWORD regPrevious;
152 regRetval=RegCreateKeyEx(
153 HKEY_LOCAL_MACHINE,
154 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
155 0,
156 "",
157 REG_OPTION_NON_VOLATILE,
158 KEY_ALL_ACCESS,
159 NULL,
160 &regKey,
161 &regPrevious);
162
163 if (regRetval==ERROR_SUCCESS)
164 {
165 RegSetValueEx(regKey,"EXEPatch",0,REG_SZ,(const uint8*)patchfile,strlen(patchfile)+1);
166
167 char message[256];
168 LoadString(NULL,IDS_SYS_RESTART,message,256);
169 char title[128];
170 LoadString(NULL,IDS_SYS_RESTART_TITLE,title,128);
171
172 MessageBox(NULL,message,title,MB_OK);
173
175 }
176 else
177 {
178 char message[256];
179 LoadString(NULL,IDS_RUNONCE_ERR,message,256);
180 char string[256];
181 sprintf(string,message,patchfile);
182 MessageBox(NULL,string,"ERROR",MB_OK);
183 }
184 }
185 //
186 // RTPatch type patch
187 //
188 else if (strcasecmp(patchfile+strlen(patchfile)-strlen(".rtp"),".rtp")==0)
189 {
190 MSG msg;
191 HWND dialog=Create_Patch_Dialog();
192 while(PeekMessage(&msg,NULL,0,0, PM_REMOVE))
193 {
194 TranslateMessage(&msg);
195 DispatchMessage(&msg);
196 }
197 HINSTANCE hInst=LoadLibrary("patchw32.dll");
198 if (hInst==NULL)
199 {
200 char message[256];
201 LoadString(NULL,IDS_ERR_MISSING_FILE,message,256);
202 char string[256];
203 sprintf(string,message,"patchw32.dll");
204 char title[128];
205 LoadString(NULL,IDS_ERROR,title,128);
206 MessageBox(NULL,string,title,MB_OK);
207 exit(-1);
208 return;
209 }
210
211 DBGMSG("Patch SKU = "<<skuIndex);
212
213
214 PATCHFUNC patchFunc;
215 patchFunc=(PATCHFUNC)GetProcAddress(hInst,"RTPatchApply32@12");
216 if (patchFunc==NULL)
217 {
218 char message[256];
219 LoadString(NULL,IDS_BAD_LIBRARY,message,256);
220 char title[128];
221 LoadString(NULL,IDS_ERROR,title,128);
222 MessageBox(NULL,message,title,MB_OK);
223 return;
224 }
225
226 char patchArgs[200];
227 sprintf(patchArgs,"\"%s\" .",patchfile);
228 int rtpErrCode=patchFunc(patchArgs,PatchCallBack,TRUE);
229 FreeLibrary(hInst); // unload the DLL
230 _unlink(patchfile); // delete the patch
231
232 DestroyWindow(dialog); // get rid of the dialog
233
234 // Don't update the registry if the patch failed to update.
235 if (rtpErrCode != 0)
236 {
237 ERRMSG("Patch error: " << rtpErrCode);
238 return;
239 }
240
241 // Now we have to update the registry so the version is correct
242 // The version is the first integer in the filename
243 // Eg: 22456_patch.rtp means version 22456 goes into the registry
244
245 // The version# starts after the last '\' char
246 char *cptr=patchfile;
247 char *tempPtr;
248 DWORD version;
249 while( (tempPtr=strchr(cptr,'\\')) !=NULL)
250 cptr=tempPtr+1;
251 if (cptr)
252 version=atol(cptr);
253 DBGMSG("VERSION TO = "<<version);
254
255
256 char string[256];
257 Wstring key;
258 // Get the InstallPath from the specified registry key
259 sprintf(string,"SKU%d",skuIndex);
260 if (config.getString(string,key)==FALSE)
261 {
262 ERRMSG("SKU is missing from config file!");
263 return;
264 }
265
266 int temp=0;
267 Wstring sku;
268 Wstring path;
269 temp=key.getToken(temp," ",sku);
270 path=key;
271 path.remove(0,temp);
272 while((*(path.get()))==' ') // remove leading spaces
273 path.remove(0,1);
274 // Open the registry key for modifying now...
275 HKEY regKey;
276 LONG regRetval;
277 regRetval=RegOpenKeyEx(HKEY_LOCAL_MACHINE,path.get(),0,
278 KEY_ALL_ACCESS,&regKey);
279 if (regRetval!=ERROR_SUCCESS)
280 DBGMSG("Can't open reg key for writing");
281 regRetval=RegSetValueEx(regKey,"Version",0,REG_DWORD,(uint8 *)&version,
282 sizeof(version));
283
284
285 // Create blocking DLG for update info
286#ifdef USE_NOTEPAD
287 {
288 Process notepad;
289
290 // same dir as game
291 strcpy(notepad.directory, ".");
292
293 // the program that grabs game patches
294 strcpy(notepad.command, "notepad");
295 strcpy(notepad.args, " launcher.txt");
296
297 Create_Process(notepad);
298 Wait_Process(notepad);
299 }
300#else
301 DialogBox(Global_instance,MAKEINTRESOURCE(IDD_CHANGELOG),NULL,(DLGPROC)Update_Info_Proc);
302#endif
303 }
304 //
305 // Execute now (without rebooting) type patch
306 //
307 else if (strcasecmp(patchfile+strlen(patchfile)-strlen(".exn"),".exn")==0)
308 {
309 Process proc;
310 strcpy(proc.directory,".");
311 strcpy(proc.command,patchfile);
312 Create_Process(proc);
313 Wait_Process(proc);
314 _unlink(patchfile);
315 }
316 //
317 // Web link type patch
318 //
319 // Im about 99.44% sure that this is completely useless.
320 //
321 else if (strcasecmp(patchfile+strlen(patchfile)-strlen(".web"),".web")==0)
322 {
323 char message[256];
324 LoadString(NULL,IDS_WEBPATCH,message,256);
325 char title[128];
326 LoadString(NULL,IDS_WEBPATCH_TITLE,title,128);
327 MessageBox(NULL,message,title,MB_OK);
328
329 FILE *in=fopen(patchfile,"r");
330 if (in!=NULL)
331 {
332 char URL[256];
333 fgets(URL,255,in);
334 fclose(in);
335 ShellExecute(NULL,NULL,URL,NULL,".",SW_SHOW);
336 _unlink(patchfile);
339 exit(0);
340 }
341 else
342 {
343 MessageBox(NULL,patchfile,"Patchfile vanished?",MB_OK);
344 }
345 }
346}
347
348
349
351{
352 HANDLE hToken;
353 TOKEN_PRIVILEGES tkp;
354
355 // Get a token for this process.
356 if (!OpenProcessToken(GetCurrentProcess(),
357 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
358 {
359 //error("OpenProcessToken");
360 }
361
362 // Get the LUID for the shutdown privilege.
363 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
364 &tkp.Privileges[0].Luid);
365
366 tkp.PrivilegeCount = 1; // one privilege to set
367 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
368
369 // Get the shutdown privilege for this process.
370 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
371 (PTOKEN_PRIVILEGES)NULL, 0);
372
373 // Cannot test the return value of AdjustTokenPrivileges.
374 if (GetLastError() != ERROR_SUCCESS)
375 {
376 //error("AdjustTokenPrivileges");
377 }
378
379 // Shut down the system and force all applications to close.
380 if (!ExitWindowsEx(EWX_REBOOT, 0))
381 {
382 // Should never happen
383 char restart[128];
384 LoadString(NULL,IDS_MUST_RESTART,restart,128);
385 MessageBox(NULL,restart,"OK",MB_OK);
386 exit(0);
387 }
388
389 MSG msg;
390 while (GetMessage(&msg, NULL, 0, 0))
391 {
392 TranslateMessage( &msg );
393 DispatchMessage( &msg );
394 }
395}
396
397
398
399//
400// Callback during the patching process
401//
402__declspec(dllexport) LPVOID CALLBACK PatchCallBack(UINT Id, LPVOID Param)
403{
404 char string[128];
405 static int fileCount=0; // number of files to be patched
406 static int currFile=0;
407
408 // Make sure our windows get updated
409 MSG msg;
410 int counter=0;
411 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE ))
412 {
413 TranslateMessage( &msg );
414 DispatchMessage( &msg );
415 counter++;
416 if (counter==100) // just in case...
417 break;
418 }
419
422
424 //g_DlgPtr->SetRTPErrCode(Id);
425
427
428 switch( Id )
429 {
430 case 1:
431 case 2:
432 // Warning message header/text
433 DBGMSG("P_MSG: "<<((char *)Param));
434 break;
435
436 case 3:
437 // Error message header
438 DBGMSG("P_MSG: "<<((char *)Param));
439 break;
440
441 case 4:
442 // Error message header/text
444 char errmsg[256];
445 LoadString(NULL,IDS_ERR_PATCH,errmsg,256);
446 MessageBox(NULL,(char *)Param,errmsg,MB_OK);
447 {
448 FILE *out=fopen("patch.err","a");
449 time_t timet=time(NULL);
450 fprintf(out,"\n\nPatch Error: %s\n",ctime(&timet));
451 fprintf(out,"%s\n",(char *)Param);
452 fclose(out);
453 }
454 break;
455
456 case 9:
457 // progress message
458 break;
459
460 case 0xa:
461 // help message
462 break;
463
464 case 0xb:
465 // patch file comment
466 break;
467
468 case 0xc:
469 // copyright message
470 // Need to return this so Foreign Lang chars don't mess up.
471 return "ANSI";
472
473 case 5:
474 // % completed
475 // so adjust the progress bar using the global Dialog pointer
477 percent=((*(UINT *)Param)*100)/0x8000;
478 SendMessage(GetDlgItem(PatchDialog,IDC_PROGRESS2),PBM_SETPOS,percent,0);
479 break;
480
481 case 6:
482 // Number of patch files
483 DBGMSG("6: "<<*((uint32 *)Param));
484 fileCount=*((uint32 *)Param);
485 currFile=0;
486 break;
487
488 case 7:
490 //LoadString(g_AppInstance, IDS_PROCESSING, lpcBuf, 256);
491 //strcpy(buf,lpcBuf);
492 //strcat(buf,(char *)Parm);
493 //g_DlgPtr->SetProgressText(buf);
494 //*g_LogFile << buf << " : ";
495 //fileModified = true;
496
497 DBGMSG("7: "<<(char *)Param);
498 SetWindowText(GetDlgItem(PatchDialog,IDC_FILENAME),(char *)Param);
499 percent=0;
500 SendMessage(GetDlgItem(PatchDialog,IDC_PROGRESS2),PBM_SETPOS,percent,0);
501
502 currFile++;
503 char xofy[64];
504 LoadString(NULL,IDS_FILE_X_OF_Y,xofy,64);
505 sprintf(string,xofy,currFile,fileCount);
506 SetWindowText(GetDlgItem(PatchDialog,IDC_CAPTION),string);
507
508 break;
509
510 case 8:
512 //LoadString(g_AppInstance, IDS_PROCCOMPLETE, lpcBuf, 256);
513 //g_DlgPtr->SetProgressText(lpcBuf);
514 //*g_LogFile << " complete" << endl;
515 percent=100;
516 SendMessage(GetDlgItem(PatchDialog,IDC_PROGRESS2),PBM_SETPOS,percent,0);
517 DBGMSG("P_DONE");
518 break;
519
520 case 0xd:
523 //Abort = TRUE;
524 //*g_LogFile << "Incorrect (or none) patch file specified in command line." << endl;
525 break;
526
527 case 0xe:
529 //Abort = TRUE;
530 //*g_LogFile << "Incorrect (or none) path specified in command line." << endl;
531 break;
532
533 case 0xf:
535 break;
536
537 case 0x10:
539 break;
540
541 case 0x11:
543 break;
544
545 case 0x12:
547 break;
548
549 case 0x13:
551 break;
552
553 case 0x14:
555 //Abort = TRUE;
556 //*g_LogFile << "Specified path is incorrect." << endl;
557 break;
558
559 case 0x16:
561 break;
562
563 case 0x15:
565 break;
566
567 default:
568 break;
569 }
570
572 return (NULL);
573 else
574 return (RetVal);
575}
#define NULL
Definition BaseType.h:92
#define TRUE
Definition BaseType.h:109
#define FALSE
Definition BaseType.h:113
bit8 Create_Process(Process &process)
Definition process.cpp:31
bit8 Wait_Process(Process &process, DWORD *exit_code)
Definition process.cpp:76
#define ERRMSG(X)
Definition wdebug.h:86
#define DBGMSG(X)
Definition wdebug.h:128
HINSTANCE Global_instance
Definition winblows.cpp:29
char bit8
Definition wstypes.h:61
unsigned int UINT
Definition bittype.h:63
unsigned long uint32
Definition bittype.h:46
unsigned char uint8
Definition bittype.h:44
unsigned long DWORD
Definition bittype.h:57
LPVOID(__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes)
#define IDC_TEXT
Definition resource.h:92
#define IDC_FILENAME
Definition resource.h:76
#define IDS_SYS_RESTART_TITLE
Definition resource.h:24
#define IDS_ERR_PATCH
Definition resource.h:33
#define IDS_ERROR
Definition resource.h:30
#define IDD_CHANGELOG
Definition resource.h:37
#define IDS_MUST_RESTART
Definition resource.h:28
#define IDC_PROGRESS2
Definition resource.h:38
#define IDC_CAPTION
Definition resource.h:41
#define IDS_WEBPATCH_TITLE
Definition resource.h:26
#define IDS_FILE_X_OF_Y
Definition resource.h:27
#define IDS_RUNONCE_ERR
Definition resource.h:29
#define IDS_ERR_MISSING_FILE
Definition resource.h:31
#define IDS_WEBPATCH
Definition resource.h:25
#define IDS_BAD_LIBRARY
Definition resource.h:32
#define IDS_SYS_RESTART
Definition resource.h:23
#define BOOL
Definition Wnd_File.h:57
bit8 getString(IN Wstring &key, OUT Wstring &value)
char directory[256]
Definition process.h:32
char command[256]
Definition process.h:33
char args[256]
Definition process.h:34
char remove(sint32 pos, sint32 count)
Definition wstring.cpp:236
char * get(void)
Definition wstring.cpp:336
sint32 getToken(int offset, char *delim, Wstring &out)
Definition wstring.cpp:566
HWND PatchDialog
Definition dialog.cpp:27
HWND Create_Patch_Dialog(void)
Definition dialog.cpp:30
void Shutdown_Computer_Now(void)
Definition patch.cpp:350
__declspec(dllexport) LPVOID CALLBACK PatchCallBack(UINT ID
int percent
Definition patch.cpp:426
int counter
Definition patch.cpp:410
bit8 Abort
Definition patch.cpp:421
BOOL CALLBACK Update_Info_Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
Definition patch.cpp:42
void Apply_Patch(char *patchfile, ConfigFile &config, int skuIndex)
Definition patch.cpp:136
UINT(CALLBACK * PATCHFUNC)(LPSTR, PATCHCALLBACK, BOOL)
Definition patch.cpp:129
LPVOID(CALLBACK * PATCHCALLBACK)(UINT, LPVOID)
Definition patch.cpp:128
MSG msg
Definition patch.cpp:409
LPVOID Param
Definition patch.cpp:126
LPVOID RetVal
Definition patch.cpp:420
HINSTANCE hInst
Definition test2.cpp:37
long time_t
Definition wolapi.h:436