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