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