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