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