xref: /plan9/sys/src/cmd/gs/src/dwinst.cpp (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999-2002, Ghostgum Software Pty Ltd.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 // $Id: dwinst.cpp,v 1.6 2004/11/18 06:48:41 ghostgum Exp $
18 
19 #define STRICT
20 #include <windows.h>
21 #include <objbase.h>
22 #include <shlobj.h>
23 #include <stdio.h>
24 #include <io.h>
25 #include <direct.h>
26 
27 #include "dwinst.h"
28 
29 #define UNINSTALLKEY TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
30 #define UNINSTALLSTRINGKEY TEXT("UninstallString")
31 #define DISPLAYNAMEKEY TEXT("DisplayName")
32 #define UNINSTALL_FILE "uninstal.txt"
33 char szSection[] = "////////////////////////////////\n";
34 
35 #ifdef _MSC_VER
36 #define mktemp(x) _mktemp(x)
37 #define chdir(x) _chdir(x)
38 #define mkdir(x) _mkdir(x)
39 #endif
40 
41 
42 
43 //////////////////////////////////////////////////////////////////////
44 // Construction/Destruction
45 //////////////////////////////////////////////////////////////////////
46 
CInstall()47 CInstall::CInstall()
48 {
49 	CoInitialize(NULL);
50 
51 	m_szTargetDir[0] = '\0';
52 	m_szTargetGroup[0] = '\0';
53 	m_szPrograms[0] = '\0';
54 	m_szMainDir[0] = '\0';
55 	AddMessageFn = NULL;
56 	SetAllUsers(FALSE);
57 }
58 
~CInstall()59 CInstall::~CInstall()
60 {
61 	CoUninitialize();
62 }
63 
CleanUp(void)64 void CInstall::CleanUp(void)
65 {
66 	// delete all temporary files
67 	if (m_fLogNew)
68 		fclose(m_fLogNew);
69 	m_fLogNew = NULL;
70 	if (m_fLogOld)
71 		fclose(m_fLogOld);
72 	m_fLogOld = NULL;
73 
74 	if (strlen(m_szRegistryNew))
75 		DeleteFile(m_szRegistryNew);
76 	m_szRegistryNew[0] = '\0';
77 
78 	if (strlen(m_szRegistryOld))
79 		DeleteFile(m_szRegistryOld);
80 	m_szRegistryOld[0] = '\0';
81 
82 	if (strlen(m_szShellNew))
83 		DeleteFile(m_szShellNew);
84 	m_szShellNew[0] = '\0';
85 
86 	if (strlen(m_szShellOld))
87 		DeleteFile(m_szShellOld);
88 	m_szShellOld[0] = '\0';
89 
90 	if (strlen(m_szFileNew))
91 		DeleteFile(m_szFileNew);
92 	m_szFileNew[0] = '\0';
93 }
94 
95 
SetMessageFunction(void (* fn)(const char *))96 void CInstall::SetMessageFunction(void(*fn)(const char *))
97 {
98 	AddMessageFn = fn;
99 }
100 
AddMessage(const char * message)101 void CInstall::AddMessage(const char *message)
102 {
103 	if (AddMessageFn)
104 		(*AddMessageFn)(message);
105 }
106 
SetTargetDir(const char * szTargetDir)107 void CInstall::SetTargetDir(const char *szTargetDir)
108 {
109 	strcpy(m_szTargetDir, szTargetDir);
110 	// remove trailing backslash
111 	char *p;
112 	p = m_szTargetDir + strlen(m_szTargetDir) - 1;
113 	if (*p == '\\')
114 		*p = '\0';
115 }
116 
SetTargetGroup(const char * szTargetGroup)117 void CInstall::SetTargetGroup(const char *szTargetGroup)
118 {
119 	strcpy(m_szTargetGroup, szTargetGroup);
120 	// remove trailing backslash
121 	char *p;
122 	p = m_szTargetGroup + strlen(m_szTargetGroup) - 1;
123 	if (*p == '\\')
124 		*p = '\0';
125 }
126 
GetMainDir()127 const char *CInstall::GetMainDir()
128 {
129 	return m_szMainDir;
130 }
131 
GetUninstallName()132 const char *CInstall::GetUninstallName()
133 {
134 	return m_szUninstallName;
135 }
136 
Init(const char * szSourceDir,const char * szFileList)137 BOOL CInstall::Init(const char *szSourceDir, const char *szFileList)
138 {
139 	FILE *f;
140 
141 	strcpy(m_szSourceDir, szSourceDir);
142 	// remove trailing backslash
143 	char *p;
144 	p = m_szSourceDir + strlen(m_szSourceDir) - 1;
145 	if (*p == '\\')
146 		*p = '\0';
147 	strcpy(m_szFileList, szFileList);
148 
149 	m_szRegistryNew[0] = m_szRegistryOld[0] =
150 		m_szShellNew[0] = m_szShellOld[0] =
151 		m_szFileNew[0] = '\0';
152 
153 	// Open list of files
154 	SetCurrentDirectory(m_szSourceDir);
155 	f = fopen(m_szFileList, "r");
156 	if (f == (FILE *)NULL) {
157 		char buf[MAXSTR];
158 		wsprintf(buf, "Failed to open \042%s\042\n", m_szFileList);
159 		AddMessage(buf);
160 		return FALSE;
161 	}
162 
163 	// get application and directory name
164 	m_szUninstallName[0] = '\0';
165 	if (!fgets(m_szUninstallName, sizeof(m_szUninstallName), f)) {
166 		AddMessage("Invalid file list\n");
167 		fclose(f);
168 		return FALSE;
169 	}
170 	if (*m_szUninstallName )
171 		m_szUninstallName[strlen(m_szUninstallName)-1] = '\0';
172 
173 	m_szMainDir[0] = '\0';
174 	if (!fgets(m_szMainDir, sizeof(m_szMainDir), f)) {
175 		AddMessage("Invalid file list\n");
176 		fclose(f);
177 		return FALSE;
178 	}
179 	if (*m_szMainDir )
180 		m_szMainDir[strlen(m_szMainDir)-1] = '\0';
181 	fclose(f);
182 
183 	// Create log directory
184 	strcpy(m_szLogDir, m_szTargetDir);
185 	strcat(m_szLogDir, "\\");
186 	strcat(m_szLogDir, m_szMainDir);
187 	MakeDir(m_szLogDir);
188 
189 	return TRUE;
190 }
191 
192 
193 //////////////////////////////////////////
194 // File installation methods
195 
InstallFiles(BOOL bNoCopy,BOOL * pbQuit)196 BOOL CInstall::InstallFiles(BOOL bNoCopy, BOOL *pbQuit)
197 {
198 	char szLogNew[MAXSTR];
199 
200 	AddMessage(bNoCopy ? "Checking" : "Copying");
201 	AddMessage(" files listed in ");
202 	AddMessage(m_szFileList);
203 	AddMessage("\n");
204 
205 	// Open list of files
206 	SetCurrentDirectory(m_szSourceDir);
207 	FILE *f = fopen(m_szFileList, "r");
208 	if (f == (FILE *)NULL) {
209 		AddMessage("Failed to open \042");
210 		AddMessage(m_szFileList);
211 		AddMessage("\042\n");
212 		return FALSE;
213 	}
214 
215 	// skip application and directory name
216 	fgets(szLogNew, sizeof(szLogNew), f);
217 	fgets(szLogNew, sizeof(szLogNew), f);
218 
219 	// Create target log
220 
221 	m_fLogNew = MakeTemp(m_szFileNew);
222 	if (!m_fLogNew) {
223 		AddMessage("Failed to create FileNew temporary file\n");
224 		return FALSE;
225 	}
226 
227 	// Copy files
228 	char line[MAXSTR];
229 	while (fgets(line, sizeof(line), f) != (char *)NULL) {
230 		if (*pbQuit)
231 			return FALSE;
232 		if (*line)
233 			line[strlen(line)-1] = '\0';
234 		if (!InstallFile(line, bNoCopy)) {
235 			fclose(f);
236 			fclose(m_fLogNew);
237 			return FALSE;
238 		}
239 	}
240 	fclose(f);
241 	fclose(m_fLogNew);
242 	m_fLogNew = NULL;
243 	return TRUE;
244 }
245 
246 
AppendFileNew(const char * filename)247 void CInstall::AppendFileNew(const char *filename)
248 {
249     FILE *f;
250     /* mark backup file for uninstall */
251     if ((f = fopen(m_szFileNew, "a")) != (FILE *)NULL) {
252 	fputs(filename, f);
253 	fputs("\n", f);
254 	fclose(f);
255     }
256 }
257 
258 // recursive mkdir
259 // requires a full path to be specified, so ignores root \
260 // apart from root \, must not contain trailing \
261 // Examples:
262 //  c:\          (OK, but useless)
263 //  c:\gstools   (OK)
264 //  c:\gstools\  (incorrect)
265 //  c:gstools    (incorrect)
266 //  gstools      (incorrect)
267 // The following UNC names should work,
268 // but didn't under Win3.1 because gs_chdir wouldn't accept UNC names
269 // Needs to be tested under Windows 95.
270 //  \\server\sharename\gstools    (OK)
271 //  \\server\sharename\           (OK, but useless)
272 //
273 
MakeDir(const char * dirname)274 BOOL CInstall::MakeDir(const char *dirname)
275 {
276 	char newdir[MAXSTR];
277 	const char *p;
278     if (strlen(dirname) < 3)
279         return -1;
280 
281     if (isalpha(dirname[0]) && dirname[1]==':' && dirname[2]=='\\') {
282         // drive mapped path
283         p = dirname+3;
284     }
285     else if (dirname[1]=='\\' && dirname[1]=='\\') {
286         // UNC path
287         p = strchr(dirname+2, '\\');    // skip servername
288         if (p == NULL)
289             return -1;
290         p++;
291         p = strchr(p, '\\');            // skip sharename
292         if (p == NULL)
293             return -1;
294     }
295     else {
296         // not full path so error
297         return -1;
298     }
299 
300     while (1) {
301         strncpy(newdir, dirname, (int)(p-dirname));
302         newdir[(int)(p-dirname)] = '\0';
303         if (chdir(newdir)) {
304             if (mkdir(newdir))
305                 return -1;
306         }
307         p++;
308         if (p >= dirname + strlen(dirname))
309             break;              // all done
310         p = strchr(p, '\\');
311         if (p == NULL)
312             p = dirname + strlen(dirname);
313     }
314 
315     return SetCurrentDirectory(dirname);
316 }
317 
ResetReadonly(const char * filename)318 void CInstall::ResetReadonly(const char *filename)
319 {
320     DWORD dwAttr = GetFileAttributes(filename);
321     if (dwAttr & FILE_ATTRIBUTE_READONLY)
322         SetFileAttributes(filename, dwAttr & (~FILE_ATTRIBUTE_READONLY));
323 }
324 
InstallFile(char * filename,BOOL bNoCopy)325 BOOL CInstall::InstallFile(char *filename, BOOL bNoCopy)
326 {
327 	char existing_name[MAXSTR];
328 	char new_name[MAXSTR];
329 	char dir_name[MAXSTR];
330 
331 	strcpy(existing_name, m_szSourceDir);
332 	strcat(existing_name, "\\");
333 	strcat(existing_name, filename);
334 	strcpy(new_name, m_szTargetDir);
335 	strcat(new_name, "\\");
336 	strcat(new_name, filename);
337 	strcpy(dir_name, new_name);
338 	char *p = strrchr(dir_name, '\\');
339 	if (p) {
340 		*p = '\0';
341 		if (!MakeDir(dir_name)) {
342 			AddMessage("Failed to make directory ");
343 			AddMessage(dir_name);
344 			AddMessage("\n");
345 			return FALSE;
346 		}
347 	}
348 	AddMessage("   ");
349 	AddMessage(new_name);
350 	AddMessage("\n");
351 
352 	if (bNoCopy) {
353 		// Don't copy files.  Leave them where they are.
354 		// Check that all files exist
355 		FILE *f;
356 		if ((f = fopen(existing_name, "r")) == (FILE *)NULL) {
357 			AddMessage("Missing file ");
358 			AddMessage(existing_name);
359 			AddMessage("\n");
360 			return FALSE;
361 		}
362 		fclose(f);
363 	}
364 	else {
365 		if (!CopyFile(existing_name, new_name, FALSE)) {
366 			char message[MAXSTR+MAXSTR+100];
367 			wsprintf(message, "Failed to copy file %s to %s\n",
368 				existing_name, new_name);
369 			AddMessage(message);
370 			return FALSE;
371 		}
372 		ResetReadonly(new_name);
373 		fputs(new_name, m_fLogNew);
374 		fputs("\n", m_fLogNew);
375 	}
376 
377 
378 	return TRUE;
379 }
380 
381 //////////////////////////////////////////
382 // Shell methods
383 
StartMenuBegin()384 BOOL CInstall::StartMenuBegin()
385 {
386 	m_fLogNew = MakeTemp(m_szShellNew);
387 	if (!m_fLogNew) {
388 		AddMessage("Failed to create ShellNew temporary file\n");
389 		return FALSE;
390 	}
391 
392 	m_fLogOld = MakeTemp(m_szShellOld);
393 	if (!m_fLogOld) {
394 		AddMessage("Failed to create ShellNew temporary file\n");
395 		return FALSE;
396 	}
397 
398 	// make folder if needed
399 	char szLink[MAXSTR];
400 	strcpy(szLink, m_szPrograms);
401 	strcat(szLink, "\\");
402 	strcat(szLink, m_szTargetGroup);
403 	if (chdir(szLink) != 0) {
404 		if (mkdir(szLink) != 0) {
405 			char buf[MAXSTR+64];
406 			wsprintf(buf, "Couldn't make Programs folder \042%s'042", szLink);
407 			AddMessage(buf);
408 			StartMenuEnd();
409 			return FALSE;
410 		}
411 	}
412 	else {
413 		fprintf(m_fLogOld, "Group=%s\n\n", szLink);
414 	}
415 	fprintf(m_fLogNew, "Group=%s\n\n", szLink);
416 
417 	return TRUE;
418 }
419 
StartMenuEnd()420 BOOL CInstall::StartMenuEnd()
421 {
422 	if (m_fLogOld)
423 		fclose(m_fLogOld);
424 	m_fLogOld = NULL;
425 	if (m_fLogNew)
426 		fclose(m_fLogNew);
427 	m_fLogNew = NULL;
428 	return TRUE;
429 }
430 
StartMenuAdd(const char * szDescription,const char * szProgram,const char * szArguments)431 BOOL CInstall::StartMenuAdd(const char *szDescription,
432 							const char *szProgram, const char *szArguments)
433 {
434 	if (!CreateShellLink(szDescription, szProgram, szArguments)) {
435 		AddMessage("Couldn't make shell link for ");
436 		AddMessage(szDescription);
437 		AddMessage("\n");
438 		StartMenuEnd();
439 		return FALSE;
440 	}
441 
442 	return TRUE;
443 }
444 
445 
CreateShellLink(LPCSTR description,LPCSTR program,LPCSTR arguments,LPCSTR icon,int nIconIndex)446 BOOL CInstall::CreateShellLink(LPCSTR description, LPCSTR program,
447 							   LPCSTR arguments, LPCSTR icon, int nIconIndex)
448 {
449 	HRESULT hres;
450 	IShellLink* psl;
451 	CHAR szLink[MAXSTR];
452 	strcpy(szLink, m_szPrograms);
453 	strcat(szLink, "\\");
454 	strcat(szLink, m_szTargetGroup);
455 	strcat(szLink, "\\");
456 	strcat(szLink, description);
457 	strcat(szLink, ".LNK");
458 	AddMessage("Adding shell link\n   ");
459 	AddMessage(szLink);
460 	AddMessage("\n");
461 
462 	// Ensure string is UNICODE.
463 	WCHAR wsz[MAX_PATH];
464 	MultiByteToWideChar(CP_ACP, 0, szLink, -1, wsz, MAX_PATH);
465 
466 	// Save old shell link
467 
468 	// Get a pointer to the IShellLink interface.
469 	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
470 		IID_IShellLink, (void **)&psl);
471 	if (SUCCEEDED(hres))    {
472 		IPersistFile* ppf;
473 		// Query IShellLink for the IPersistFile interface.
474 		hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
475 		if (SUCCEEDED(hres))       {
476 			// Load the shell link.
477 			hres = ppf->Load(wsz, STGM_READ);
478 			if (SUCCEEDED(hres)) {
479 				// Resolve the link.
480 				hres = psl->Resolve(HWND_DESKTOP, SLR_ANY_MATCH);
481 				if (SUCCEEDED(hres)) {
482 					// found it, so save details
483 					CHAR szTemp[MAXSTR];
484 					WIN32_FIND_DATA wfd;
485 					int i;
486 
487 
488 					fprintf(m_fLogOld, "Name=%s\n", szLink);
489 					hres = psl->GetPath(szTemp, MAXSTR, (WIN32_FIND_DATA *)&wfd,
490 						SLGP_SHORTPATH );
491 					if (SUCCEEDED(hres))
492 						fprintf(m_fLogOld, "Path=%s\n", szTemp);
493 					hres = psl->GetDescription(szTemp, MAXSTR);
494 					if (SUCCEEDED(hres))
495 						fprintf(m_fLogOld, "Description=%s\n", szTemp);
496 					hres = psl->GetArguments(szTemp, MAXSTR);
497 					if (SUCCEEDED(hres) && (szTemp[0] != '\0'))
498 						fprintf(m_fLogOld, "Arguments=%s\n", szTemp);
499 					hres = psl->GetWorkingDirectory(szTemp, MAXSTR);
500 					if (SUCCEEDED(hres) && (szTemp[0] != '\0'))
501 						fprintf(m_fLogOld, "Directory=%s\n", szTemp);
502 					hres = psl->GetIconLocation(szTemp, MAXSTR, &i);
503 					if (SUCCEEDED(hres) && (szTemp[0] != '\0')) {
504 						fprintf(m_fLogOld, "IconLocation=%s\n", szTemp);
505 						fprintf(m_fLogOld, "IconIndex=%d\n", i);
506 					}
507 					fprintf(m_fLogOld, "\n");
508 				}
509 			}
510 			// Release pointer to IPersistFile.
511 			ppf->Release();
512 		}
513 		// Release pointer to IShellLink.
514 		psl->Release();
515 	}
516 
517 
518 	// Save new shell link
519 
520 	// Get a pointer to the IShellLink interface.
521 	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
522 		IID_IShellLink, (void **)&psl);
523 	if (SUCCEEDED(hres))    {
524 		IPersistFile* ppf;
525 		// Query IShellLink for the IPersistFile interface for
526 		// saving the shell link in persistent storage.
527 		hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
528 		if (SUCCEEDED(hres)) {
529 			fprintf(m_fLogNew, "Name=%s\n", szLink);
530 
531 			// Set the path to the shell link target.
532 			hres = psl->SetPath(program);
533 			if (!SUCCEEDED(hres))
534 				AddMessage("SetPath failed!");
535 			fprintf(m_fLogNew, "Path=%s\n", program);
536 			// Set the description of the shell link.
537 			hres = psl->SetDescription(description);
538 			if (!SUCCEEDED(hres))
539 				AddMessage("SetDescription failed!");
540 			fprintf(m_fLogNew, "Description=%s\n", description);
541 			if (arguments != (LPCSTR)NULL) {
542 				// Set the arguments of the shell link target.
543 				hres = psl->SetArguments(arguments);
544 				if (!SUCCEEDED(hres))
545 					AddMessage("SetArguments failed!");
546 				fprintf(m_fLogNew, "Arguments=%s\n", arguments);
547 			}
548 			if (icon != (LPCSTR)NULL) {
549 				// Set the arguments of the shell link target.
550 				hres = psl->SetIconLocation(icon, nIconIndex);
551 				if (!SUCCEEDED(hres))
552 					AddMessage("SetIconLocation failed!");
553 				fprintf(m_fLogNew, "IconLocation=%s\n", icon);
554 				fprintf(m_fLogNew, "IconIndex=%d\n", nIconIndex);
555 			}
556 
557 			// Save the link via the IPersistFile::Save method.
558 			hres = ppf->Save(wsz, TRUE);
559 			// Release pointer to IPersistFile.
560 			ppf->Release();
561 		}
562 		// Release pointer to IShellLink.
563 		psl->Release();
564 		fprintf(m_fLogNew, "\n");
565 	}
566 
567 	return (hres == 0);
568 }
569 
570 
571 //////////////////////////////////////////
572 // Registry methods
573 
574 void
reg_quote(char * d,const char * s)575 reg_quote(char *d, const char *s)
576 {
577     while (*s) {
578 		if (*s == '\\')
579 			*d++ = '\\';
580 		*d++ = *s++;
581     }
582     *d = *s;
583 }
584 
UpdateRegistryBegin()585 BOOL CInstall::UpdateRegistryBegin()
586 {
587 	const char regheader[]="REGEDIT4\n";
588 	m_fLogNew = MakeTemp(m_szRegistryNew);
589 	if (!m_fLogNew) {
590 		AddMessage("Failed to create RegistryNew temporary file\n");
591 		return FALSE;
592 	}
593 	fputs(regheader, m_fLogNew);
594 
595 	m_fLogOld = MakeTemp(m_szRegistryOld);
596 	if (!m_fLogOld) {
597 		AddMessage("Failed to create RegistryOld temporary file\n");
598 		UpdateRegistryEnd();
599 		return FALSE;
600 	}
601 	fputs(regheader, m_fLogOld);
602 
603 	return TRUE;
604 }
605 
UpdateRegistryEnd()606 BOOL CInstall::UpdateRegistryEnd()
607 {
608 	if (m_fLogNew)
609 		fclose(m_fLogNew);
610 	m_fLogNew = NULL;
611 	if (m_fLogOld)
612 		fclose(m_fLogOld);
613 	m_fLogOld = NULL;
614 	return TRUE;
615 }
616 
UpdateRegistryKey(const char * product,const char * version)617 BOOL CInstall::UpdateRegistryKey(const char *product, const char *version)
618 {
619 	const char hkey_name[] = "HKEY_LOCAL_MACHINE";
620 	const HKEY hkey_key = HKEY_LOCAL_MACHINE;
621 	const char key_format[] = "\n[%s\\%s]\n";
622 
623 	/* Create default registry entries */
624 	HKEY hkey;
625 	LONG lrc;
626 	char name[MAXSTR];
627 
628 	// Create/Open application key
629 	sprintf(name, "SOFTWARE\\%s", product);
630 	lrc = RegOpenKey(hkey_key, name, &hkey);
631 	if (lrc == ERROR_SUCCESS) {
632 		fprintf(m_fLogOld, key_format, hkey_name, name);
633 	}
634 	else {
635 		lrc = RegCreateKey(hkey_key, name, &hkey);
636 		if (lrc == ERROR_SUCCESS)
637 			fprintf(m_fLogNew, key_format, hkey_name, name);
638 	}
639 	if (lrc == ERROR_SUCCESS)
640 		RegCloseKey(hkey);
641 
642 	// Create/Open application version key
643 	sprintf(name, "SOFTWARE\\%s\\%s", product, version);
644 
645 	AddMessage("   ");
646 	AddMessage(hkey_name);
647 	AddMessage("\\");
648 	AddMessage(name);
649 	AddMessage("\n");
650 	lrc = RegOpenKey(hkey_key, name, &hkey);
651 	if (lrc == ERROR_SUCCESS)
652 		fprintf(m_fLogOld, key_format, hkey_name, name);
653 	else
654 		lrc = RegCreateKey(hkey_key, name, &hkey);
655 	if (lrc == ERROR_SUCCESS) {
656 		fprintf(m_fLogNew, key_format, hkey_name, name);
657 	}
658 	else {
659 		UpdateRegistryEnd();
660 	}
661 	return TRUE;
662 }
663 
UpdateRegistryValue(const char * product,const char * version,const char * name,const char * value)664 BOOL CInstall::UpdateRegistryValue(const char *product, const char *version,
665 								   const char *name, const char *value)
666 {
667 	char appver[MAXSTR];
668 	BOOL flag = FALSE;
669 	HKEY hkey;
670 	// Open application/version key
671 	sprintf(appver, "SOFTWARE\\%s\\%s", product, version);
672 
673 	if (RegOpenKey(HKEY_LOCAL_MACHINE, appver, &hkey)
674 		== ERROR_SUCCESS) {
675 		flag = SetRegistryValue(hkey, name, value);
676 		RegCloseKey(hkey);
677 	}
678 
679 	return flag;
680 }
681 
SetRegistryValue(HKEY hkey,const char * value_name,const char * value)682 BOOL CInstall::SetRegistryValue(HKEY hkey, const char *value_name, const char *value)
683 {
684 	char buf[MAXSTR];
685 	char qbuf[MAXSTR];
686 	DWORD cbData;
687 	DWORD keytype;
688 
689 	cbData = sizeof(buf);
690 	keytype =  REG_SZ;
691 	if (RegQueryValueEx(hkey, value_name, 0, &keytype,
692 		(LPBYTE)buf, &cbData) == ERROR_SUCCESS) {
693 		reg_quote(qbuf, buf);
694 		fprintf(m_fLogOld, "\042%s\042=\042%s\042\n", value_name, qbuf);
695 	}
696 	reg_quote(qbuf, value);
697 	fprintf(m_fLogNew, "\042%s\042=\042%s\042\n", value_name, qbuf);
698 	AddMessage("      ");
699 	AddMessage(value_name);
700 	AddMessage("=");
701 	AddMessage(value);
702 	AddMessage("\n");
703 	if (RegSetValueEx(hkey, value_name, 0, REG_SZ,
704 		(CONST BYTE *)value, strlen(value)+1) != ERROR_SUCCESS)
705 		return FALSE;
706 	return TRUE;
707 }
708 
709 ////////////////////////////////////
710 // Uninstall
711 
712 
WriteUninstall(const char * szProg,BOOL bNoCopy)713 BOOL CInstall::WriteUninstall(const char *szProg, BOOL bNoCopy)
714 {
715 	LONG rc;
716 	HKEY hkey;
717 	HKEY hsubkey;
718 	char buffer[MAXSTR];
719 	char ungsprog[MAXSTR];
720 
721 	lstrcpy(ungsprog, m_szTargetDir);
722 	lstrcat(ungsprog, "\\");
723 	lstrcat(ungsprog, szProg);
724 
725 	lstrcpy(buffer, m_szSourceDir);
726 	lstrcat(buffer, "\\");
727 	lstrcat(buffer, szProg);
728 
729 	if (bNoCopy) {
730 		// Don't copy files.  Leave them where they are.
731 		// Check that all files exist
732 		FILE *f;
733 		if ((f = fopen(buffer, "r")) == (FILE *)NULL) {
734 			AddMessage("Missing file ");
735 			AddMessage(buffer);
736 			AddMessage("\n");
737 			return FALSE;
738 		}
739 		fclose(f);
740 	}
741 	else if (!CopyFile(buffer, ungsprog, FALSE)) {
742 		char message[MAXSTR+MAXSTR+100];
743 		wsprintf(message, "Failed to copy file %s to %s", buffer, ungsprog);
744 		AddMessage(message);
745 		return FALSE;
746 	}
747 	ResetReadonly(ungsprog);
748 
749 	/* write registry entries for uninstall */
750 	if ((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, UNINSTALLKEY, 0,
751 		KEY_ALL_ACCESS, &hkey)) != ERROR_SUCCESS) {
752 		/* failed to open key, so try to create it */
753         rc = RegCreateKey(HKEY_LOCAL_MACHINE, UNINSTALLKEY, &hkey);
754 	}
755 	if (rc == ERROR_SUCCESS) {
756 		// Uninstall key for program
757 		if (RegCreateKey(hkey, m_szUninstallName, &hsubkey) == ERROR_SUCCESS) {
758 			RegSetValueEx(hsubkey, DISPLAYNAMEKEY, 0, REG_SZ,
759 				(CONST BYTE *)m_szUninstallName, lstrlen(m_szUninstallName)+1);
760 			lstrcpy(buffer, ungsprog);
761 			lstrcat(buffer, " \042");
762 			lstrcat(buffer, m_szTargetDir);
763 			lstrcat(buffer, "\\");
764 			lstrcat(buffer, m_szMainDir);
765 			lstrcat(buffer, "\\");
766 			lstrcat(buffer, UNINSTALL_FILE);
767 			lstrcat(buffer, "\042");
768 			AddMessage("   ");
769 			AddMessage(m_szUninstallName);
770 			AddMessage("=");
771 			AddMessage(buffer);
772 			AddMessage("\n");
773 			RegSetValueEx(hsubkey, UNINSTALLSTRINGKEY, 0, REG_SZ,
774 				(CONST BYTE *)buffer, lstrlen(buffer)+1);
775 			RegCloseKey(hsubkey);
776 		}
777 
778 		RegCloseKey(hkey);
779 	}
780 	return TRUE;
781 }
782 
783 
784 void
CopyFileContents(FILE * df,FILE * sf)785 CInstall::CopyFileContents(FILE *df, FILE *sf)
786 {
787 	char buf[MAXSTR];
788 	int count;
789 	while ((count = fread(buf, 1, sizeof(buf), sf)) != 0)
790 		fwrite(buf, 1, count, df);
791 }
792 
MakeTemp(char * fname)793 FILE *CInstall::MakeTemp(char *fname)
794 {
795 	char *temp;
796 	if ( (temp = getenv("TEMP")) == NULL )
797 		strcpy(fname, m_szTargetDir);
798 	else
799 		strcpy(fname, temp);
800 
801 	/* Prevent X's in path from being converted by mktemp. */
802 	for ( temp = fname; *temp; temp++ ) {
803 		*temp = (char)tolower(*temp);
804 		if (*temp == '/')
805 			*temp = '\\';
806 	}
807 	if ( strlen(fname) && (fname[strlen(fname)-1] != '\\') )
808 		strcat(fname, "\\");
809 
810 	strcat(fname, "gsXXXXXX");
811 	mktemp(fname);
812 	AddMessage("Creating temporary file ");
813 	AddMessage(fname);
814 	AddMessage("\n");
815 	return fopen(fname, "w");
816 }
817 
MakeLog()818 BOOL CInstall::MakeLog()
819 {
820 	FILE *f, *lf;
821 	char szFileName[MAXSTR];
822 	char szLogDir[MAXSTR];
823 	strcpy(szLogDir, m_szTargetDir);
824 	strcat(szLogDir, "\\");
825 	strcat(szLogDir, m_szMainDir);
826 	strcat(szLogDir, "\\");
827 
828 	strcpy(szFileName, szLogDir);
829 	strcat(szFileName, UNINSTALL_FILE);
830 	lf = fopen(szFileName, "w");
831 	if (lf == (FILE *)NULL) {
832 		AddMessage("Can't create uninstall log");
833 		CleanUp();
834 		return FALSE;
835 	}
836 	fputs(szSection, lf);
837 	fputs("UninstallName\n", lf);
838 	fputs(m_szUninstallName, lf);
839 	fputs("\n\n", lf);
840 
841 	if (strlen(m_szRegistryNew) &&
842 		(f = fopen(m_szRegistryNew, "r")) != (FILE *)NULL) {
843 		fputs(szSection, lf);
844 		fputs("RegistryNew\n", lf);
845 		CopyFileContents(lf, f);
846 		fputs("\n", lf);
847 		fclose(f);
848 		DeleteFile(m_szRegistryNew);
849 		m_szRegistryNew[0] = '\0';
850 	}
851 
852 	if (strlen(m_szRegistryOld) &&
853 		(f = fopen(m_szRegistryOld, "r")) != (FILE *)NULL) {
854 		fputs(szSection, lf);
855 		fputs("RegistryOld\n", lf);
856 		CopyFileContents(lf, f);
857 		fputs("\n", lf);
858 		fclose(f);
859 		DeleteFile(m_szRegistryOld);
860 		m_szRegistryOld[0] = '\0';
861 	}
862 
863 	if (strlen(m_szShellNew) &&
864 		(f = fopen(m_szShellNew, "r")) != (FILE *)NULL) {
865 		fputs(szSection, lf);
866 		fputs("ShellNew\n", lf);
867 		CopyFileContents(lf, f);
868 		fputs("\n", lf);
869 		fclose(f);
870 		DeleteFile(m_szShellNew);
871 		m_szShellNew[0] = '\0';
872 	}
873 
874 	if (strlen(m_szShellOld) &&
875 		(f = fopen(m_szShellOld, "r")) != (FILE *)NULL) {
876 		fputs(szSection, lf);
877 		fputs("ShellOld\n", lf);
878 		CopyFileContents(lf, f);
879 		fputs("\n", lf);
880 		fclose(f);
881 		DeleteFile(m_szShellOld);
882 		m_szShellOld[0] = '\0';
883 	}
884 
885 	if (strlen(m_szFileNew) &&
886 		(f = fopen(m_szFileNew, "r")) != (FILE *)NULL) {
887 		fputs(szSection, lf);
888 		fputs("FileNew\n", lf);
889 		CopyFileContents(lf, f);
890 		fputs("\n", lf);
891 		fclose(f);
892 		DeleteFile(m_szFileNew);
893 		m_szFileNew[0] = '\0';
894 	}
895 
896 	fputs(szSection, lf);
897 	fclose(lf);
898 
899 	return TRUE;
900 }
901 
GetPrograms(BOOL bUseCommon,char * buf,int buflen)902 BOOL CInstall::GetPrograms(BOOL bUseCommon, char *buf, int buflen)
903 {
904 	// Get the directory for the Program menu. This is
905 	// stored in the Registry under HKEY_CURRENT_USER\Software\
906 	// Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Programs.
907 	LONG rc;
908 	HKEY hCU;
909 	DWORD dwType;
910 	ULONG ulSize = buflen;
911 	HKEY hrkey = HKEY_CURRENT_USER;
912 	if (bUseCommon)
913 		hrkey = HKEY_LOCAL_MACHINE;
914 	if (RegOpenKeyEx(hrkey,
915 		"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
916 		0,KEY_QUERY_VALUE,
917 		&hCU) == ERROR_SUCCESS)    {
918 		rc = RegQueryValueEx( hCU,
919 			bUseCommon ? "Common Programs" : "Programs",
920 			NULL,
921 			&dwType,
922 			(unsigned char *)buf,
923 			&ulSize);
924 		RegCloseKey(hCU);
925 		return TRUE;
926 	}
927 	return FALSE;
928 
929 #ifdef NOTUSED
930 	// This is an alternate version, but it needs
931 	// Internet Explorer 4.0 with Web Integrated Desktop.
932 	// It does not work with the standard
933 	// Windows 95, Windows NT 4.0, Internet Explorer 3.0,
934 	// and Internet Explorer 4.0 without Web Integrated Desktop.
935 
936 	HRESULT rc;
937 	m_szPrograms[0] = '\0';
938 	int nFolder = CSIDL_PROGRAMS;
939 	if (bUseCommon)
940 		nFolder = CSIDL_COMMON_PROGRAMS;
941 
942 	rc = SHGetSpecialFolderPath(HWND_DESKTOP, m_szPrograms,
943 		nFolder, FALSE);
944 	return (rc == NOERROR);
945 #endif
946 
947 }
948 
SetAllUsers(BOOL bUseCommon)949 BOOL CInstall::SetAllUsers(BOOL bUseCommon)
950 {
951 	m_bUseCommon = bUseCommon;
952 	return GetPrograms(bUseCommon, m_szPrograms, sizeof(m_szPrograms));
953 }
954 
955 
956 //////////////////////////////////////////////////////////////////////
957