blob: 597bd9e8eb0919259b45a36abb1956ba6d18611c [file] [log] [blame]
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001/*
2 * Written by Thomas Heller, May 2000
3 *
4 * $Id$
5 */
6
7/*
8 * Windows Installer program for distutils.
9 *
10 * (a kind of self-extracting zip-file)
11 *
12 * At runtime, the exefile has appended:
13 * - compressed setup-data in ini-format, containing the following sections:
14 * [metadata]
15 * author=Greg Ward
16 * author_email=gward@python.net
17 * description=Python Distribution Utilities
18 * licence=Python
19 * name=Distutils
20 * url=http://www.python.org/sigs/distutils-sig/
21 * version=0.9pre
22 *
23 * [Setup]
24 * info= text to be displayed in the edit-box
25 * title= to be displayed by this program
26 * target_version = if present, python version required
27 * pyc_compile = if 0, do not compile py to pyc
28 * pyo_compile = if 0, do not compile py to pyo
29 *
30 * - a struct meta_data_hdr, describing the above
31 * - a zip-file, containing the modules to be installed.
32 * for the format see http://www.pkware.com/appnote.html
33 *
34 * What does this program do?
35 * - the setup-data is uncompressed and written to a temporary file.
36 * - setup-data is queried with GetPrivateProfile... calls
37 * - [metadata] - info is displayed in the dialog box
38 * - The registry is searched for installations of python
39 * - The user can select the python version to use.
40 * - The python-installation directory (sys.prefix) is displayed
41 * - When the start-button is pressed, files from the zip-archive
42 * are extracted to the file system. All .py filenames are stored
43 * in a list.
44 */
45/*
46 * Includes now an uninstaller.
47 */
48
49/*
50 * To Do:
51 *
52 * display some explanation when no python version is found
53 * instead showing the user an empty listbox to select something from.
54 *
55 * Finish the code so that we can use other python installations
56 * additionaly to those found in the registry,
57 * and then #define USE_OTHER_PYTHON_VERSIONS
58 *
59 * - install a help-button, which will display something meaningful
60 * to the poor user.
61 * text to the user
62 * - should there be a possibility to display a README file
63 * before starting the installation (if one is present in the archive)
64 * - more comments about what the code does(?)
65 *
66 * - evolve this into a full blown installer (???)
67 */
68
69#include <windows.h>
70#include <commctrl.h>
71#include <imagehlp.h>
72#include <objbase.h>
73#include <shlobj.h>
74#include <objidl.h>
75#include "resource.h"
76
77#include <stdio.h>
78#include <stdlib.h>
79#include <stdarg.h>
80#include <string.h>
81#include <time.h>
82
83#include "archive.h"
84
85/* Only for debugging!
86 static int dprintf(char *fmt, ...)
87 {
88 char Buffer[4096];
89 va_list marker;
90 int result;
91
92 va_start(marker, fmt);
93 result = wvsprintf(Buffer, fmt, marker);
94 OutputDebugString(Buffer);
95 return result;
96 }
97*/
98
99/* Bah: global variables */
100FILE *logfile;
101
102char modulename[MAX_PATH];
103
104HWND hwndMain;
105HWND hDialog;
106
107char *ini_file; /* Full pathname of ini-file */
108/* From ini-file */
109char info[4096]; /* [Setup] info= */
110char title[80]; /* [Setup] title=, contains package name
111 including version: "Distutils-1.0.1" */
112char target_version[10]; /* [Setup] target_version=, required python
113 version or empty string */
114char build_info[80]; /* [Setup] build_info=, distutils version
115 and build date */
116
117char meta_name[80]; /* package name without version like
118 'Distutils' */
119char install_script[MAX_PATH];
120
121
122int py_major, py_minor; /* Python version selected for installation */
123
124char *arc_data; /* memory mapped archive */
125DWORD arc_size; /* number of bytes in archive */
126int exe_size; /* number of bytes for exe-file portion */
127char python_dir[MAX_PATH];
128char pythondll[MAX_PATH];
129BOOL pyc_compile, pyo_compile;
130
131BOOL success; /* Installation successfull? */
132
133HANDLE hBitmap;
134char *bitmap_bytes;
135
136
137#define WM_NUMFILES WM_USER+1
138/* wParam: 0, lParam: total number of files */
139#define WM_NEXTFILE WM_USER+2
140/* wParam: number of this file */
141/* lParam: points to pathname */
142
143enum { UNSPECIFIED, ALWAYS, NEVER } allow_overwrite = UNSPECIFIED;
144
145static BOOL notify(int code, char *fmt, ...);
146
147/* Note: If scheme.prefix is nonempty, it must end with a '\'! */
148/* Note: purelib must be the FIRST entry! */
149SCHEME old_scheme[] = {
150 { "PURELIB", "" },
151 { "PLATLIB", "" },
152 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
153 { "SCRIPTS", "Scripts\\" },
154 { "DATA", "" },
155 { NULL, NULL },
156};
157
158SCHEME new_scheme[] = {
159 { "PURELIB", "Lib\\site-packages\\" },
160 { "PLATLIB", "Lib\\site-packages\\" },
161 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
162 { "SCRIPTS", "Scripts\\" },
163 { "DATA", "" },
164 { NULL, NULL },
165};
166
167static void unescape(char *dst, char *src, unsigned size)
168{
169 char *eon;
170 char ch;
171
172 while (src && *src && (size > 2)) {
173 if (*src == '\\') {
174 switch (*++src) {
175 case 'n':
176 ++src;
177 *dst++ = '\r';
178 *dst++ = '\n';
179 size -= 2;
180 break;
181 case 'r':
182 ++src;
183 *dst++ = '\r';
184 --size;
185 break;
186 case '0': case '1': case '2': case '3':
187 ch = (char)strtol(src, &eon, 8);
188 if (ch == '\n') {
189 *dst++ = '\r';
190 --size;
191 }
192 *dst++ = ch;
193 --size;
194 src = eon;
195 }
196 } else {
197 *dst++ = *src++;
198 --size;
199 }
200 }
201 *dst = '\0';
202}
203
204static struct tagFile {
205 char *path;
206 struct tagFile *next;
207} *file_list = NULL;
208
209static void add_to_filelist(char *path)
210{
211 struct tagFile *p;
212 p = (struct tagFile *)malloc(sizeof(struct tagFile));
213 p->path = strdup(path);
214 p->next = file_list;
215 file_list = p;
216}
217
218static int do_compile_files(int (__cdecl * PyRun_SimpleString)(char *),
219 int optimize)
220{
221 struct tagFile *p;
222 int total, n;
223 char Buffer[MAX_PATH + 64];
224 int errors = 0;
225
226 total = 0;
227 p = file_list;
228 while (p) {
229 ++total;
230 p = p->next;
231 }
232 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETRANGE, 0,
233 MAKELPARAM(0, total));
234 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETPOS, 0, 0);
235
236 n = 0;
237 p = file_list;
238 while (p) {
239 ++n;
240 wsprintf(Buffer,
241 "import py_compile; py_compile.compile (r'%s')",
242 p->path);
243 if (PyRun_SimpleString(Buffer)) {
244 ++errors;
245 }
246 /* We send the notification even if the files could not
247 * be created so that the uninstaller will remove them
248 * in case they are created later.
249 */
250 wsprintf(Buffer, "%s%c", p->path, optimize ? 'o' : 'c');
251 notify(FILE_CREATED, Buffer);
252
253 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETPOS, n, 0);
254 SetDlgItemText(hDialog, IDC_INFO, p->path);
255 p = p->next;
256 }
257 return errors;
258}
259
260#define DECLPROC(dll, result, name, args)\
261 typedef result (*__PROC__##name) args;\
262 result (*name)args = (__PROC__##name)GetProcAddress(dll, #name)
263
264
265#define DECLVAR(dll, type, name)\
266 type *name = (type*)GetProcAddress(dll, #name)
267
268typedef void PyObject;
269
270
271/*
272 * Returns number of files which failed to compile,
273 * -1 if python could not be loaded at all
274 */
275static int compile_filelist(HINSTANCE hPython, BOOL optimize_flag)
276{
277 DECLPROC(hPython, void, Py_Initialize, (void));
278 DECLPROC(hPython, void, Py_SetProgramName, (char *));
279 DECLPROC(hPython, void, Py_Finalize, (void));
280 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
281 DECLPROC(hPython, PyObject *, PySys_GetObject, (char *));
282 DECLVAR(hPython, int, Py_OptimizeFlag);
283
284 int errors = 0;
285 struct tagFile *p = file_list;
286
287 if (!p)
288 return 0;
289
290 if (!Py_Initialize || !Py_SetProgramName || !Py_Finalize)
291 return -1;
292
293 if (!PyRun_SimpleString || !PySys_GetObject || !Py_OptimizeFlag)
294 return -1;
295
296 *Py_OptimizeFlag = optimize_flag ? 1 : 0;
297 Py_SetProgramName(modulename);
298 Py_Initialize();
299
300 errors += do_compile_files(PyRun_SimpleString, optimize_flag);
301 Py_Finalize();
302
303 return errors;
304}
305
306typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
307
308struct PyMethodDef {
309 char *ml_name;
310 PyCFunction ml_meth;
311 int ml_flags;
312 char *ml_doc;
313};
314typedef struct PyMethodDef PyMethodDef;
315
316void *(*g_Py_BuildValue)(char *, ...);
317int (*g_PyArg_ParseTuple)(PyObject *, char *, ...);
318
319PyObject *g_PyExc_ValueError;
320PyObject *g_PyExc_OSError;
321
322PyObject *(*g_PyErr_Format)(PyObject *, char *, ...);
323
324#define DEF_CSIDL(name) { name, #name }
325
326struct {
327 int nFolder;
328 char *name;
329} csidl_names[] = {
330 /* Startup menu for all users.
331 NT only */
332 DEF_CSIDL(CSIDL_COMMON_STARTMENU),
333 /* Startup menu. */
334 DEF_CSIDL(CSIDL_STARTMENU),
335
336/* DEF_CSIDL(CSIDL_COMMON_APPDATA), */
337/* DEF_CSIDL(CSIDL_LOCAL_APPDATA), */
338 /* Repository for application-specific data.
339 Needs Internet Explorer 4.0 */
340 DEF_CSIDL(CSIDL_APPDATA),
341
342 /* The desktop for all users.
343 NT only */
344 DEF_CSIDL(CSIDL_COMMON_DESKTOPDIRECTORY),
345 /* The desktop. */
346 DEF_CSIDL(CSIDL_DESKTOPDIRECTORY),
347
348 /* Startup folder for all users.
349 NT only */
350 DEF_CSIDL(CSIDL_COMMON_STARTUP),
351 /* Startup folder. */
352 DEF_CSIDL(CSIDL_STARTUP),
353
354 /* Programs item in the start menu for all users.
355 NT only */
356 DEF_CSIDL(CSIDL_COMMON_PROGRAMS),
357 /* Program item in the user's start menu. */
358 DEF_CSIDL(CSIDL_PROGRAMS),
359
360/* DEF_CSIDL(CSIDL_PROGRAM_FILES_COMMON), */
361/* DEF_CSIDL(CSIDL_PROGRAM_FILES), */
362
363 /* Virtual folder containing fonts. */
364 DEF_CSIDL(CSIDL_FONTS),
365};
366
367#define DIM(a) (sizeof(a) / sizeof((a)[0]))
368
369static PyObject *FileCreated(PyObject *self, PyObject *args)
370{
371 char *path;
372 if (!g_PyArg_ParseTuple(args, "s", &path))
373 return NULL;
374 notify(FILE_CREATED, path);
375 return g_Py_BuildValue("");
376}
377
378static PyObject *DirectoryCreated(PyObject *self, PyObject *args)
379{
380 char *path;
381 if (!g_PyArg_ParseTuple(args, "s", &path))
382 return NULL;
383 notify(DIR_CREATED, path);
384 return g_Py_BuildValue("");
385}
386
387static PyObject *GetSpecialFolderPath(PyObject *self, PyObject *args)
388{
389 char *name;
390 char lpszPath[MAX_PATH];
391 int i;
392 static HRESULT (WINAPI *My_SHGetSpecialFolderPath)(HWND hwnd,
393 LPTSTR lpszPath,
394 int nFolder,
395 BOOL fCreate);
396
397 if (!My_SHGetSpecialFolderPath) {
398 HINSTANCE hLib = LoadLibrary("shell32.dll");
399 if (!hLib) {
400 g_PyErr_Format(g_PyExc_OSError,
401 "function not available");
402 return NULL;
403 }
404 My_SHGetSpecialFolderPath = (BOOL (WINAPI *)(HWND, LPTSTR,
405 int, BOOL))
406 GetProcAddress(hLib,
407 "SHGetSpecialFolderPathA");
408 }
409
410 if (!g_PyArg_ParseTuple(args, "s", &name))
411 return NULL;
412
413 if (!My_SHGetSpecialFolderPath) {
414 g_PyErr_Format(g_PyExc_OSError, "function not available");
415 return NULL;
416 }
417
418 for (i = 0; i < DIM(csidl_names); ++i) {
419 if (0 == strcmpi(csidl_names[i].name, name)) {
420 int nFolder;
421 nFolder = csidl_names[i].nFolder;
422 if (My_SHGetSpecialFolderPath(NULL, lpszPath,
423 nFolder, 0))
424 return g_Py_BuildValue("s", lpszPath);
425 else {
426 g_PyErr_Format(g_PyExc_OSError,
427 "no such folder (%s)", name);
428 return NULL;
429 }
430
431 }
432 };
433 g_PyErr_Format(g_PyExc_ValueError, "unknown CSIDL (%s)", name);
434 return NULL;
435}
436
437static PyObject *CreateShortcut(PyObject *self, PyObject *args)
438{
439 char *path; /* path and filename */
440 char *description;
441 char *filename;
442
443 char *arguments = NULL;
444 char *iconpath = NULL;
445 int iconindex = 0;
446 char *workdir = NULL;
447
448 WCHAR wszFilename[MAX_PATH];
449
450 IShellLink *ps1 = NULL;
451 IPersistFile *pPf = NULL;
452
453 HRESULT hr;
454
455 hr = CoInitialize(NULL);
456 if (FAILED(hr)) {
457 g_PyErr_Format(g_PyExc_OSError,
458 "CoInitialize failed, error 0x%x", hr);
459 goto error;
460 }
461
462 if (!g_PyArg_ParseTuple(args, "sss|sssi",
463 &path, &description, &filename,
464 &arguments, &workdir, &iconpath, &iconindex))
465 return NULL;
466
467 hr = CoCreateInstance(&CLSID_ShellLink,
468 NULL,
469 CLSCTX_INPROC_SERVER,
470 &IID_IShellLink,
471 &ps1);
472 if (FAILED(hr)) {
473 g_PyErr_Format(g_PyExc_OSError,
474 "CoCreateInstance failed, error 0x%x", hr);
475 goto error;
476 }
477
478 hr = ps1->lpVtbl->QueryInterface(ps1, &IID_IPersistFile,
479 (void **)&pPf);
480 if (FAILED(hr)) {
481 g_PyErr_Format(g_PyExc_OSError,
482 "QueryInterface(IPersistFile) error 0x%x", hr);
483 goto error;
484 }
485
486
487 hr = ps1->lpVtbl->SetPath(ps1, path);
488 if (FAILED(hr)) {
489 g_PyErr_Format(g_PyExc_OSError,
490 "SetPath() failed, error 0x%x", hr);
491 goto error;
492 }
493
494 hr = ps1->lpVtbl->SetDescription(ps1, description);
495 if (FAILED(hr)) {
496 g_PyErr_Format(g_PyExc_OSError,
497 "SetDescription() failed, error 0x%x", hr);
498 goto error;
499 }
500
501 if (arguments) {
502 hr = ps1->lpVtbl->SetArguments(ps1, arguments);
503 if (FAILED(hr)) {
504 g_PyErr_Format(g_PyExc_OSError,
505 "SetArguments() error 0x%x", hr);
506 goto error;
507 }
508 }
509
510 if (iconpath) {
511 hr = ps1->lpVtbl->SetIconLocation(ps1, iconpath, iconindex);
512 if (FAILED(hr)) {
513 g_PyErr_Format(g_PyExc_OSError,
514 "SetIconLocation() error 0x%x", hr);
515 goto error;
516 }
517 }
518
519 if (workdir) {
520 hr = ps1->lpVtbl->SetWorkingDirectory(ps1, workdir);
521 if (FAILED(hr)) {
522 g_PyErr_Format(g_PyExc_OSError,
523 "SetWorkingDirectory() error 0x%x", hr);
524 goto error;
525 }
526 }
527
528 MultiByteToWideChar(CP_ACP, 0,
529 filename, -1,
530 wszFilename, MAX_PATH);
531
532 hr = pPf->lpVtbl->Save(pPf, wszFilename, TRUE);
533 if (FAILED(hr)) {
534 g_PyErr_Format(g_PyExc_OSError,
535 "Save() failed, error 0x%x", hr);
536 goto error;
537 }
538
539 pPf->lpVtbl->Release(pPf);
540 ps1->lpVtbl->Release(ps1);
541 CoUninitialize();
542 return g_Py_BuildValue("");
543
544 error:
545 if (pPf)
546 pPf->lpVtbl->Release(pPf);
547
548 if (ps1)
549 ps1->lpVtbl->Release(ps1);
550
551 CoUninitialize();
552
553 return NULL;
554}
555
556#define METH_VARARGS 0x0001
557
558PyMethodDef meth[] = {
559 {"create_shortcut", CreateShortcut, METH_VARARGS, NULL},
560 {"get_special_folder_path", GetSpecialFolderPath, METH_VARARGS, NULL},
561 {"file_created", FileCreated, METH_VARARGS, NULL},
562 {"directory_created", DirectoryCreated, METH_VARARGS, NULL},
563};
564
565/*
566 * This function returns one of the following error codes:
567 * 1 if the Python-dll does not export the functions we need
568 * 2 if no install-script is specified in pathname
569 * 3 if the install-script file could not be opened
570 * the return value of PyRun_SimpleFile() otherwise,
571 * which is 0 if everything is ok, -1 if an exception had occurred
572 * in the install-script.
573 */
574
575static int
576run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
577{
578 DECLPROC(hPython, void, Py_Initialize, (void));
579 DECLPROC(hPython, int, PySys_SetArgv, (int, char **));
580 DECLPROC(hPython, int, PyRun_SimpleFile, (FILE *, char *));
581 DECLPROC(hPython, void, Py_Finalize, (void));
582 DECLPROC(hPython, PyObject *, PyImport_ImportModule, (char *));
583 DECLPROC(hPython, int, PyObject_SetAttrString,
584 (PyObject *, char *, PyObject *));
585 DECLPROC(hPython, PyObject *, PyObject_GetAttrString,
586 (PyObject *, char *));
587 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
588 DECLPROC(hPython, PyObject *, PyCFunction_New,
589 (PyMethodDef *, PyObject *));
590 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
591 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
592
593 PyObject *mod;
594
595 int result = 0;
596 FILE *fp;
597
598 if (!Py_Initialize || !PySys_SetArgv
599 || !PyRun_SimpleFile || !Py_Finalize)
600 return 1;
601
602 if (!PyImport_ImportModule || !PyObject_SetAttrString
603 || !Py_BuildValue)
604 return 1;
605
606 if (!PyCFunction_New || !PyArg_ParseTuple || !PyErr_Format)
607 return 1;
608
609 if (!PyObject_GetAttrString)
610 return 1;
611
612 g_Py_BuildValue = Py_BuildValue;
613 g_PyArg_ParseTuple = PyArg_ParseTuple;
614 g_PyErr_Format = PyErr_Format;
615
616 if (pathname == NULL || pathname[0] == '\0')
617 return 2;
618
619 fp = fopen(pathname, "r");
620 if (!fp) {
621 fprintf(stderr, "Could not open postinstall-script %s\n",
622 pathname);
623 return 3;
624 }
625
626 SetDlgItemText(hDialog, IDC_INFO, "Running Script...");
627
628 Py_Initialize();
629
630 mod = PyImport_ImportModule("__builtin__");
631 if (mod) {
632 int i;
633
634 g_PyExc_ValueError = PyObject_GetAttrString(mod,
635 "ValueError");
636 g_PyExc_OSError = PyObject_GetAttrString(mod, "OSError");
637 for (i = 0; i < DIM(meth); ++i) {
638 PyObject_SetAttrString(mod, meth[i].ml_name,
639 PyCFunction_New(&meth[i], NULL));
640 }
641 }
642
643 PySys_SetArgv(argc, argv);
644 result = PyRun_SimpleFile(fp, pathname);
645 Py_Finalize();
646
647 fclose(fp);
648
649 return result;
650}
651
652static BOOL SystemError(int error, char *msg)
653{
654 char Buffer[1024];
655 int n;
656
657 if (error) {
658 LPVOID lpMsgBuf;
659 FormatMessage(
660 FORMAT_MESSAGE_ALLOCATE_BUFFER |
661 FORMAT_MESSAGE_FROM_SYSTEM,
662 NULL,
663 error,
664 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
665 (LPSTR)&lpMsgBuf,
666 0,
667 NULL
668 );
669 strncpy(Buffer, lpMsgBuf, sizeof(Buffer));
670 LocalFree(lpMsgBuf);
671 } else
672 Buffer[0] = '\0';
673 n = lstrlen(Buffer);
674 _snprintf(Buffer+n, sizeof(Buffer)-n, msg);
675 MessageBox(hwndMain, Buffer, "Runtime Error", MB_OK | MB_ICONSTOP);
676 return FALSE;
677}
678
679static BOOL AskOverwrite(char *filename)
680{
681 int result;
682 again:
683 if (allow_overwrite == ALWAYS)
684 return TRUE;
685 if (allow_overwrite == NEVER)
686 return FALSE;
687 result = MessageBox(hDialog,
688 "Overwrite existing files?\n"
689 "\n"
690 "Press YES to ALWAYS overwrite existing files,\n"
691 "press NO to NEVER overwrite existing files.",
692 "Overwrite options",
693 MB_YESNO | MB_ICONQUESTION);
694 if (result == IDYES)
695 allow_overwrite = ALWAYS;
696 else if (result == IDNO)
697 allow_overwrite = NEVER;
698 goto again;
699}
700
701static BOOL notify (int code, char *fmt, ...)
702{
703 char Buffer[1024];
704 va_list marker;
705 BOOL result = TRUE;
706 int a, b;
707 char *cp;
708
709 va_start(marker, fmt);
710 _vsnprintf(Buffer, sizeof(Buffer), fmt, marker);
711
712 switch (code) {
713/* Questions */
714 case CAN_OVERWRITE:
715 result = AskOverwrite(Buffer);
716 break;
717
718/* Information notification */
719 case DIR_CREATED:
720 if (logfile)
721 fprintf(logfile, "100 Made Dir: %s\n", fmt);
722 break;
723
724 case FILE_CREATED:
725 if (logfile)
726 fprintf(logfile, "200 File Copy: %s\n", fmt);
727 goto add_to_filelist_label;
728 break;
729
730 case FILE_OVERWRITTEN:
731 if (logfile)
732 fprintf(logfile, "200 File Overwrite: %s\n", fmt);
733 add_to_filelist_label:
734 if ((cp = strrchr(fmt, '.')) && (0 == strcmp (cp, ".py")))
735 add_to_filelist(fmt);
736 break;
737
738/* Error Messages */
739 case ZLIB_ERROR:
740 MessageBox(GetFocus(), Buffer, "Error",
741 MB_OK | MB_ICONWARNING);
742 break;
743
744 case SYSTEM_ERROR:
745 SystemError(GetLastError(), Buffer);
746 break;
747
748 case NUM_FILES:
749 a = va_arg(marker, int);
750 b = va_arg(marker, int);
751 SendMessage(hDialog, WM_NUMFILES, 0, MAKELPARAM(0, a));
752 SendMessage(hDialog, WM_NEXTFILE, b,(LPARAM)fmt);
753 }
754 va_end(marker);
755
756 return result;
757}
758
759static char *MapExistingFile(char *pathname, DWORD *psize)
760{
761 HANDLE hFile, hFileMapping;
762 DWORD nSizeLow, nSizeHigh;
763 char *data;
764
765 hFile = CreateFile(pathname,
766 GENERIC_READ, FILE_SHARE_READ, NULL,
767 OPEN_EXISTING,
768 FILE_ATTRIBUTE_NORMAL, NULL);
769 if (hFile == INVALID_HANDLE_VALUE)
770 return NULL;
771 nSizeLow = GetFileSize(hFile, &nSizeHigh);
772 hFileMapping = CreateFileMapping(hFile,
773 NULL, PAGE_READONLY, 0, 0, NULL);
774 CloseHandle(hFile);
775
776 if (hFileMapping == INVALID_HANDLE_VALUE)
777 return NULL;
778
779 data = MapViewOfFile(hFileMapping,
780 FILE_MAP_READ, 0, 0, 0);
781
782 CloseHandle(hFileMapping);
783 *psize = nSizeLow;
784 return data;
785}
786
787
788static void create_bitmap(HWND hwnd)
789{
790 BITMAPFILEHEADER *bfh;
791 BITMAPINFO *bi;
792 HDC hdc;
793
794 if (!bitmap_bytes)
795 return;
796
797 if (hBitmap)
798 return;
799
800 hdc = GetDC(hwnd);
801
802 bfh = (BITMAPFILEHEADER *)bitmap_bytes;
803 bi = (BITMAPINFO *)(bitmap_bytes + sizeof(BITMAPFILEHEADER));
804
805 hBitmap = CreateDIBitmap(hdc,
806 &bi->bmiHeader,
807 CBM_INIT,
808 bitmap_bytes + bfh->bfOffBits,
809 bi,
810 DIB_RGB_COLORS);
811 ReleaseDC(hwnd, hdc);
812}
813
814static char *ExtractIniFile(char *data, DWORD size, int *pexe_size)
815{
816 /* read the end of central directory record */
817 struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
818 (struct eof_cdir)];
819
820 int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
821 pe->ofsCDir;
822
823 int ofs = arc_start - sizeof (struct meta_data_hdr);
824
825 /* read meta_data info */
826 struct meta_data_hdr *pmd = (struct meta_data_hdr *)&data[ofs];
827 char *src, *dst;
828 char *ini_file;
829 char tempdir[MAX_PATH];
830
831 if (pe->tag != 0x06054b50) {
832 return NULL;
833 }
834
835 if (pmd->tag != 0x1234567A || ofs < 0) {
836 return NULL;
837 }
838
839 if (pmd->bitmap_size) {
840 /* Store pointer to bitmap bytes */
841 bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
842 }
843
844 *pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
845
846 src = ((char *)pmd) - pmd->uncomp_size;
847 ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
848 if (!ini_file)
849 return NULL;
850 if (!GetTempPath(sizeof(tempdir), tempdir)
851 || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
852 SystemError(GetLastError(),
853 "Could not create temporary file");
854 return NULL;
855 }
856
857 dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
858 0, 0, NULL/*notify*/);
859 if (!dst)
860 return NULL;
861 memcpy(dst, src, pmd->uncomp_size);
862 UnmapViewOfFile(dst);
863 return ini_file;
864}
865
866static void PumpMessages(void)
867{
868 MSG msg;
869 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
870 TranslateMessage(&msg);
871 DispatchMessage(&msg);
872 }
873}
874
875LRESULT CALLBACK
876WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
877{
878 HDC hdc;
879 HFONT hFont;
880 int h;
881 PAINTSTRUCT ps;
882 switch (msg) {
883 case WM_PAINT:
884 hdc = BeginPaint(hwnd, &ps);
885 h = GetSystemMetrics(SM_CYSCREEN) / 10;
886 hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
887 0, 0, 0, 0, 0, 0, 0, "Times Roman");
888 hFont = SelectObject(hdc, hFont);
889 SetBkMode(hdc, TRANSPARENT);
890 TextOut(hdc, 15, 15, title, strlen(title));
891 SetTextColor(hdc, RGB(255, 255, 255));
892 TextOut(hdc, 10, 10, title, strlen(title));
893 DeleteObject(SelectObject(hdc, hFont));
894 EndPaint(hwnd, &ps);
895 return 0;
896 }
897 return DefWindowProc(hwnd, msg, wParam, lParam);
898}
899
900static HWND CreateBackground(char *title)
901{
902 WNDCLASS wc;
903 HWND hwnd;
904 char buffer[4096];
905
906 wc.style = CS_VREDRAW | CS_HREDRAW;
907 wc.lpfnWndProc = WindowProc;
908 wc.cbWndExtra = 0;
909 wc.cbClsExtra = 0;
910 wc.hInstance = GetModuleHandle(NULL);
911 wc.hIcon = NULL;
912 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
913 wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
914 wc.lpszMenuName = NULL;
915 wc.lpszClassName = "SetupWindowClass";
916
917 if (!RegisterClass(&wc))
918 MessageBox(hwndMain,
919 "Could not register window class",
920 "Setup.exe", MB_OK);
921
922 wsprintf(buffer, "Setup %s", title);
923 hwnd = CreateWindow("SetupWindowClass",
924 buffer,
925 0,
926 0, 0,
927 GetSystemMetrics(SM_CXFULLSCREEN),
928 GetSystemMetrics(SM_CYFULLSCREEN),
929 NULL,
930 NULL,
931 GetModuleHandle(NULL),
932 NULL);
933 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
934 UpdateWindow(hwnd);
935 return hwnd;
936}
937
938/*
939 * Center a window on the screen
940 */
941static void CenterWindow(HWND hwnd)
942{
943 RECT rc;
944 int w, h;
945
946 GetWindowRect(hwnd, &rc);
947 w = GetSystemMetrics(SM_CXSCREEN);
948 h = GetSystemMetrics(SM_CYSCREEN);
949 MoveWindow(hwnd,
950 (w - (rc.right-rc.left))/2,
951 (h - (rc.bottom-rc.top))/2,
952 rc.right-rc.left, rc.bottom-rc.top, FALSE);
953}
954
955#include <prsht.h>
956
957BOOL CALLBACK
958IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
959{
960 LPNMHDR lpnm;
961 char Buffer[4096];
962
963 switch (msg) {
964 case WM_INITDIALOG:
965 create_bitmap(hwnd);
966 if(hBitmap)
967 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
968 IMAGE_BITMAP, (LPARAM)hBitmap);
969 CenterWindow(GetParent(hwnd));
970 wsprintf(Buffer,
971 "This Wizard will install %s on your computer. "
972 "Click Next to continue "
973 "or Cancel to exit the Setup Wizard.",
974 meta_name);
975 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
976 SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
977 SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
978 return FALSE;
979
980 case WM_NOTIFY:
981 lpnm = (LPNMHDR) lParam;
982
983 switch (lpnm->code) {
984 case PSN_SETACTIVE:
985 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
986 break;
987
988 case PSN_WIZNEXT:
989 break;
990
991 case PSN_RESET:
992 break;
993
994 default:
995 break;
996 }
997 }
998 return FALSE;
999}
1000
1001#ifdef USE_OTHER_PYTHON_VERSIONS
1002/* These are really private variables used to communicate
1003 * between StatusRoutine and CheckPythonExe
1004 */
1005char bound_image_dll[_MAX_PATH];
1006int bound_image_major;
1007int bound_image_minor;
1008
1009static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
1010 PSTR ImageName,
1011 PSTR DllName,
1012 ULONG Va,
1013 ULONG Parameter)
1014{
1015 char fname[_MAX_PATH];
1016 int int_version;
1017
1018 switch(reason) {
1019 case BindOutOfMemory:
1020 case BindRvaToVaFailed:
1021 case BindNoRoomInImage:
1022 case BindImportProcedureFailed:
1023 break;
1024
1025 case BindImportProcedure:
1026 case BindForwarder:
1027 case BindForwarderNOT:
1028 case BindImageModified:
1029 case BindExpandFileHeaders:
1030 case BindImageComplete:
1031 case BindSymbolsNotUpdated:
1032 case BindMismatchedSymbols:
1033 case BindImportModuleFailed:
1034 break;
1035
1036 case BindImportModule:
1037 if (1 == sscanf(DllName, "python%d", &int_version)) {
1038 SearchPath(NULL, DllName, NULL, sizeof(fname),
1039 fname, NULL);
1040 strcpy(bound_image_dll, fname);
1041 bound_image_major = int_version / 10;
1042 bound_image_minor = int_version % 10;
1043 OutputDebugString("BOUND ");
1044 OutputDebugString(fname);
1045 OutputDebugString("\n");
1046 }
1047 break;
1048 }
1049 return TRUE;
1050}
1051
1052/*
1053 */
1054static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1055{
1056 void (__cdecl * Py_Initialize)(void);
1057 void (__cdecl * Py_SetProgramName)(char *);
1058 void (__cdecl * Py_Finalize)(void);
1059 void* (__cdecl * PySys_GetObject)(char *);
1060 void (__cdecl * PySys_SetArgv)(int, char **);
1061 char* (__cdecl * Py_GetPrefix)(void);
1062 char* (__cdecl * Py_GetPath)(void);
1063 HINSTANCE hPython;
1064 LPSTR prefix = NULL;
1065 int (__cdecl * PyRun_SimpleString)(char *);
1066
1067 {
1068 char Buffer[256];
1069 wsprintf(Buffer, "PYTHONHOME=%s", exe);
1070 *strrchr(Buffer, '\\') = '\0';
1071// MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1072 _putenv(Buffer);
1073 _putenv("PYTHONPATH=");
1074 }
1075
1076 hPython = LoadLibrary(dll);
1077 if (!hPython)
1078 return NULL;
1079 Py_Initialize = (void (*)(void))GetProcAddress
1080 (hPython,"Py_Initialize");
1081
1082 PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1083 (hPython,"PySys_SetArgv");
1084
1085 PyRun_SimpleString = (int (*)(char *))GetProcAddress
1086 (hPython,"PyRun_SimpleString");
1087
1088 Py_SetProgramName = (void (*)(char *))GetProcAddress
1089 (hPython,"Py_SetProgramName");
1090
1091 PySys_GetObject = (void* (*)(char *))GetProcAddress
1092 (hPython,"PySys_GetObject");
1093
1094 Py_GetPrefix = (char * (*)(void))GetProcAddress
1095 (hPython,"Py_GetPrefix");
1096
1097 Py_GetPath = (char * (*)(void))GetProcAddress
1098 (hPython,"Py_GetPath");
1099
1100 Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1101 "Py_Finalize");
1102 Py_SetProgramName(exe);
1103 Py_Initialize();
1104 PySys_SetArgv(1, &exe);
1105
1106 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1107 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
1108
1109 Py_Finalize();
1110 FreeLibrary(hPython);
1111
1112 return prefix;
1113}
1114
1115static BOOL
1116CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1117{
1118 bound_image_dll[0] = '\0';
1119 if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1120 pathname,
1121 NULL,
1122 NULL,
1123 StatusRoutine))
1124 return SystemError(0, "Could not bind image");
1125 if (bound_image_dll[0] == '\0')
1126 return SystemError(0, "Does not seem to be a python executable");
1127 *pmajor = bound_image_major;
1128 *pminor = bound_image_minor;
1129 if (version && *version) {
1130 char core_version[12];
1131 wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1132 if (strcmp(version, core_version))
1133 return SystemError(0, "Wrong Python version");
1134 }
1135 get_sys_prefix(pathname, bound_image_dll);
1136 return TRUE;
1137}
1138
1139/*
1140 * Browse for other python versions. Insert it into the listbox specified
1141 * by hwnd. version, if not NULL or empty, is the version required.
1142 */
1143static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1144{
1145 char vers_name[_MAX_PATH + 80];
1146 DWORD itemindex;
1147 OPENFILENAME of;
1148 char pathname[_MAX_PATH];
1149 DWORD result;
1150
1151 strcpy(pathname, "python.exe");
1152
1153 memset(&of, 0, sizeof(of));
1154 of.lStructSize = sizeof(OPENFILENAME);
1155 of.hwndOwner = GetParent(hwnd);
1156 of.hInstance = NULL;
1157 of.lpstrFilter = "python.exe\0python.exe\0";
1158 of.lpstrCustomFilter = NULL;
1159 of.nMaxCustFilter = 0;
1160 of.nFilterIndex = 1;
1161 of.lpstrFile = pathname;
1162 of.nMaxFile = sizeof(pathname);
1163 of.lpstrFileTitle = NULL;
1164 of.nMaxFileTitle = 0;
1165 of.lpstrInitialDir = NULL;
1166 of.lpstrTitle = "Python executable";
1167 of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1168 of.lpstrDefExt = "exe";
1169
1170 result = GetOpenFileName(&of);
1171 if (result) {
1172 int major, minor;
1173 if (!CheckPythonExe(pathname, version, &major, &minor)) {
1174 return FALSE;
1175 }
1176 *strrchr(pathname, '\\') = '\0';
1177 wsprintf(vers_name, "Python Version %d.%d in %s",
1178 major, minor, pathname);
1179 itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1180 (LPARAM)(LPSTR)vers_name);
1181 SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1182 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1183 (LPARAM)(LPSTR)strdup(pathname));
1184 return TRUE;
1185 }
1186 return FALSE;
1187}
1188#endif /* USE_OTHER_PYTHON_VERSIONS */
1189
1190
1191/*
1192 * Fill the listbox specified by hwnd with all python versions found
1193 * in the registry. version, if not NULL or empty, is the version
1194 * required.
1195 */
1196static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1197{
1198 DWORD index = 0;
1199 char core_version[80];
1200 HKEY hKey;
1201 BOOL result = TRUE;
1202 DWORD bufsize;
1203
1204 if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1205 "Software\\Python\\PythonCore",
1206 0, KEY_READ, &hKey))
1207 return FALSE;
1208 bufsize = sizeof(core_version);
1209 while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1210 core_version, &bufsize, NULL,
1211 NULL, NULL, NULL)) {
1212 char subkey_name[80], vers_name[80], prefix_buf[MAX_PATH+1];
1213 int itemindex;
1214 DWORD value_size;
1215 HKEY hk;
1216
1217 bufsize = sizeof(core_version);
1218 ++index;
1219 if (version && *version && strcmp(version, core_version))
1220 continue;
1221
1222 wsprintf(vers_name, "Python Version %s (found in registry)",
1223 core_version);
1224 wsprintf(subkey_name,
1225 "Software\\Python\\PythonCore\\%s\\InstallPath",
1226 core_version);
1227 value_size = sizeof(subkey_name);
1228 if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
1229 if (ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL, prefix_buf,
1230 &value_size)) {
1231 itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
1232 (LPARAM)(LPSTR)vers_name);
1233 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1234 (LPARAM)(LPSTR)strdup(prefix_buf));
1235 }
1236 RegCloseKey(hk);
1237 }
1238 }
1239 RegCloseKey(hKey);
1240 return result;
1241}
1242
1243/* Return the installation scheme depending on Python version number */
1244SCHEME *GetScheme(int major, int minor)
1245{
1246 if (major > 2)
1247 return new_scheme;
1248 else if((major == 2) && (minor >= 2))
1249 return new_scheme;
1250 return old_scheme;
1251}
1252
1253BOOL CALLBACK
1254SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1255{
1256 LPNMHDR lpnm;
1257
1258 switch (msg) {
1259 case WM_INITDIALOG:
1260 if (hBitmap)
1261 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1262 IMAGE_BITMAP, (LPARAM)hBitmap);
1263 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1264 HKEY_LOCAL_MACHINE, target_version);
1265 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1266 HKEY_CURRENT_USER, target_version);
1267 { /* select the last entry which is the highest python
1268 version found */
1269 int count;
1270 count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1271 LB_GETCOUNT, 0, 0);
1272 if (count && count != LB_ERR)
1273 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1274 count-1, 0);
1275
1276 /* If a specific Python version is required,
1277 * display a prominent notice showing this fact.
1278 */
1279 if (target_version && target_version[0]) {
1280 char buffer[4096];
1281 wsprintf(buffer,
1282 "Python %s is required for this package. "
1283 "Select installation to use:",
1284 target_version);
1285 SetDlgItemText(hwnd, IDC_TITLE, buffer);
1286 }
1287
1288 if (count == 0) {
1289 char Buffer[4096];
1290 char *msg;
1291 if (target_version && target_version[0]) {
1292 wsprintf(Buffer,
1293 "Python version %s required, which was not found"
1294 " in the registry.", target_version);
1295 msg = Buffer;
1296 } else
1297 msg = "No Python installation found in the registry.";
1298 MessageBox(hwnd, msg, "Cannot install",
1299 MB_OK | MB_ICONSTOP);
1300 }
1301 }
1302 goto UpdateInstallDir;
1303 break;
1304
1305 case WM_COMMAND:
1306 switch (LOWORD(wParam)) {
1307/*
1308 case IDC_OTHERPYTHON:
1309 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1310 target_version))
1311 goto UpdateInstallDir;
1312 break;
1313*/
1314 case IDC_VERSIONS_LIST:
1315 switch (HIWORD(wParam)) {
1316 int id;
1317 char *cp;
1318 case LBN_SELCHANGE:
1319 UpdateInstallDir:
1320 PropSheet_SetWizButtons(GetParent(hwnd),
1321 PSWIZB_BACK | PSWIZB_NEXT);
1322 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1323 LB_GETCURSEL, 0, 0);
1324 if (id == LB_ERR) {
1325 PropSheet_SetWizButtons(GetParent(hwnd),
1326 PSWIZB_BACK);
1327 SetDlgItemText(hwnd, IDC_PATH, "");
1328 SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1329 strcpy(python_dir, "");
1330 strcpy(pythondll, "");
1331 } else {
1332 char *pbuf;
1333 int result;
1334 PropSheet_SetWizButtons(GetParent(hwnd),
1335 PSWIZB_BACK | PSWIZB_NEXT);
1336 /* Get the python directory */
1337 cp = (LPSTR)SendDlgItemMessage(hwnd,
1338 IDC_VERSIONS_LIST,
1339 LB_GETITEMDATA,
1340 id,
1341 0);
1342 strcpy(python_dir, cp);
1343 SetDlgItemText(hwnd, IDC_PATH, python_dir);
1344 /* retrieve the python version and pythondll to use */
1345 result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1346 LB_GETTEXTLEN, (WPARAM)id, 0);
1347 pbuf = (char *)malloc(result + 1);
1348 if (pbuf) {
1349 /* guess the name of the python-dll */
1350 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1351 LB_GETTEXT, (WPARAM)id,
1352 (LPARAM)pbuf);
1353 result = sscanf(pbuf, "Python Version %d.%d",
1354 &py_major, &py_minor);
1355 if (result == 2)
1356#ifdef _DEBUG
1357 wsprintf(pythondll, "c:\\python22\\PCBuild\\python%d%d_d.dll",
1358 py_major, py_minor);
1359#else
1360 wsprintf(pythondll, "python%d%d.dll",
1361 py_major, py_minor);
1362#endif
1363 free(pbuf);
1364 } else
1365 strcpy(pythondll, "");
1366 /* retrieve the scheme for this version */
1367 {
1368 char install_path[_MAX_PATH];
1369 SCHEME *scheme = GetScheme(py_major, py_minor);
1370 strcpy(install_path, python_dir);
1371 if (install_path[strlen(install_path)-1] != '\\')
1372 strcat(install_path, "\\");
1373 strcat(install_path, scheme[0].prefix);
1374 SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1375 }
1376 }
1377 }
1378 break;
1379 }
1380 return 0;
1381
1382 case WM_NOTIFY:
1383 lpnm = (LPNMHDR) lParam;
1384
1385 switch (lpnm->code) {
1386 int id;
1387 case PSN_SETACTIVE:
1388 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1389 LB_GETCURSEL, 0, 0);
1390 if (id == LB_ERR)
1391 PropSheet_SetWizButtons(GetParent(hwnd),
1392 PSWIZB_BACK);
1393 else
1394 PropSheet_SetWizButtons(GetParent(hwnd),
1395 PSWIZB_BACK | PSWIZB_NEXT);
1396 break;
1397
1398 case PSN_WIZNEXT:
1399 break;
1400
1401 case PSN_WIZFINISH:
1402 break;
1403
1404 case PSN_RESET:
1405 break;
1406
1407 default:
1408 break;
1409 }
1410 }
1411 return 0;
1412}
1413
1414static BOOL OpenLogfile(char *dir)
1415{
1416 char buffer[_MAX_PATH+1];
1417 time_t ltime;
1418 struct tm *now;
1419 long result;
1420 HKEY hKey, hSubkey;
1421 char subkey_name[256];
1422 static char KeyName[] =
1423 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1424 DWORD disposition;
1425
1426 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1427 KeyName,
1428 0,
1429 KEY_CREATE_SUB_KEY,
1430 &hKey);
1431 if (result != ERROR_SUCCESS) {
1432 if (result == ERROR_ACCESS_DENIED) {
1433 MessageBox(GetFocus(),
1434 "You do not seem to have sufficient access rights\n"
1435 "on this machine to install this software",
1436 NULL,
1437 MB_OK | MB_ICONSTOP);
1438 return FALSE;
1439 } else {
1440 MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1441 }
1442 }
1443
1444 sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1445 logfile = fopen(buffer, "a");
1446 time(&ltime);
1447 now = localtime(&ltime);
1448 strftime(buffer, sizeof(buffer),
1449 "*** Installation started %Y/%m/%d %H:%M ***\n",
1450 localtime(&ltime));
1451 fprintf(logfile, buffer);
1452 fprintf(logfile, "Source: %s\n", modulename);
1453
1454 sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
1455
1456 result = RegCreateKeyEx(hKey, subkey_name,
1457 0, NULL, 0,
1458 KEY_WRITE,
1459 NULL,
1460 &hSubkey,
1461 &disposition);
1462
1463 if (result != ERROR_SUCCESS)
1464 MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
1465
1466 RegCloseKey(hKey);
1467
1468 if (disposition == REG_CREATED_NEW_KEY)
1469 fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
1470
1471 sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
1472
1473 result = RegSetValueEx(hSubkey, "DisplayName",
1474 0,
1475 REG_SZ,
1476 buffer,
1477 strlen(buffer)+1);
1478
1479 if (result != ERROR_SUCCESS)
1480 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1481
1482 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1483 KeyName, subkey_name, "DisplayName", buffer);
1484
1485 {
1486 FILE *fp;
1487 sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1488 fp = fopen(buffer, "wb");
1489 fwrite(arc_data, exe_size, 1, fp);
1490 fclose(fp);
1491
1492 sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1493 dir, meta_name, dir, meta_name);
1494
1495 result = RegSetValueEx(hSubkey, "UninstallString",
1496 0,
1497 REG_SZ,
1498 buffer,
1499 strlen(buffer)+1);
1500
1501 if (result != ERROR_SUCCESS)
1502 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1503
1504 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1505 KeyName, subkey_name, "UninstallString", buffer);
1506 }
1507 return TRUE;
1508}
1509
1510static void CloseLogfile(void)
1511{
1512 char buffer[_MAX_PATH+1];
1513 time_t ltime;
1514 struct tm *now;
1515
1516 time(&ltime);
1517 now = localtime(&ltime);
1518 strftime(buffer, sizeof(buffer),
1519 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1520 localtime(&ltime));
1521 fprintf(logfile, buffer);
1522 if (logfile)
1523 fclose(logfile);
1524}
1525
1526BOOL CALLBACK
1527InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1528{
1529 LPNMHDR lpnm;
1530 char Buffer[4096];
1531 SCHEME *scheme;
1532
1533 switch (msg) {
1534 case WM_INITDIALOG:
1535 if (hBitmap)
1536 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1537 IMAGE_BITMAP, (LPARAM)hBitmap);
1538 wsprintf(Buffer,
1539 "Click Next to begin the installation of %s. "
1540 "If you want to review or change any of your "
1541 " installation settings, click Back. "
1542 "Click Cancel to exit the wizard.",
1543 meta_name);
1544 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1545 break;
1546
1547 case WM_NUMFILES:
1548 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1549 PumpMessages();
1550 return TRUE;
1551
1552 case WM_NEXTFILE:
1553 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1554 0);
1555 SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1556 PumpMessages();
1557 return TRUE;
1558
1559 case WM_NOTIFY:
1560 lpnm = (LPNMHDR) lParam;
1561
1562 switch (lpnm->code) {
1563 case PSN_SETACTIVE:
1564 PropSheet_SetWizButtons(GetParent(hwnd),
1565 PSWIZB_BACK | PSWIZB_NEXT);
1566 break;
1567
1568 case PSN_WIZFINISH:
1569 break;
1570
1571 case PSN_WIZNEXT:
1572 /* Handle a Next button click here */
1573 hDialog = hwnd;
1574
1575 /* Make sure the installation directory name ends in a */
1576 /* backslash */
1577 if (python_dir[strlen(python_dir)-1] != '\\')
1578 strcat(python_dir, "\\");
1579 /* Strip the trailing backslash again */
1580 python_dir[strlen(python_dir)-1] = '\0';
1581
1582 if (!OpenLogfile(python_dir))
1583 break;
1584
1585/*
1586 * The scheme we have to use depends on the Python version...
1587 if sys.version < "2.2":
1588 WINDOWS_SCHEME = {
1589 'purelib': '$base',
1590 'platlib': '$base',
1591 'headers': '$base/Include/$dist_name',
1592 'scripts': '$base/Scripts',
1593 'data' : '$base',
1594 }
1595 else:
1596 WINDOWS_SCHEME = {
1597 'purelib': '$base/Lib/site-packages',
1598 'platlib': '$base/Lib/site-packages',
1599 'headers': '$base/Include/$dist_name',
1600 'scripts': '$base/Scripts',
1601 'data' : '$base',
1602 }
1603*/
1604 scheme = GetScheme(py_major, py_minor);
1605
1606 /* Extract all files from the archive */
1607 SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
1608 success = unzip_archive(scheme,
1609 python_dir, arc_data,
1610 arc_size, notify);
1611 /* Compile the py-files */
1612 if (pyc_compile) {
1613 int errors;
1614 HINSTANCE hPython;
1615 SetDlgItemText(hwnd, IDC_TITLE,
1616 "Compiling files to .pyc...");
1617
1618 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
1619 hPython = LoadLibrary(pythondll);
1620 if (hPython) {
1621 errors = compile_filelist(hPython, FALSE);
1622 FreeLibrary(hPython);
1623 }
1624 /* Compilation errors are intentionally ignored:
1625 * Python2.0 contains a bug which will result
1626 * in sys.path containing garbage under certain
1627 * circumstances, and an error message will only
1628 * confuse the user.
1629 */
1630 }
1631 if (pyo_compile) {
1632 int errors;
1633 HINSTANCE hPython;
1634 SetDlgItemText(hwnd, IDC_TITLE,
1635 "Compiling files to .pyo...");
1636
1637 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
1638 hPython = LoadLibrary(pythondll);
1639 if (hPython) {
1640 errors = compile_filelist(hPython, TRUE);
1641 FreeLibrary(hPython);
1642 }
1643 /* Errors ignored: see above */
1644 }
1645
1646
1647 break;
1648
1649 case PSN_RESET:
1650 break;
1651
1652 default:
1653 break;
1654 }
1655 }
1656 return 0;
1657}
1658
1659
1660BOOL CALLBACK
1661FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1662{
1663 LPNMHDR lpnm;
1664
1665 switch (msg) {
1666 case WM_INITDIALOG:
1667 if (hBitmap)
1668 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1669 IMAGE_BITMAP, (LPARAM)hBitmap);
1670 if (!success)
1671 SetDlgItemText(hwnd, IDC_INFO, "Installation failed.");
1672
1673 /* async delay: will show the dialog box completely before
1674 the install_script is started */
1675 PostMessage(hwnd, WM_USER, 0, 0L);
1676 return TRUE;
1677
1678 case WM_USER:
1679
1680 if (install_script && install_script[0]) {
1681 char fname[MAX_PATH];
1682 char *tempname;
1683 FILE *fp;
1684 char buffer[4096];
1685 int n;
1686 HCURSOR hCursor;
1687 HINSTANCE hPython;
1688
1689 char *argv[3] = {NULL, "-install", NULL};
1690
1691 SetDlgItemText(hwnd, IDC_TITLE,
1692 "Please wait while running postinstall script...");
1693 strcpy(fname, python_dir);
1694 strcat(fname, "\\Scripts\\");
1695 strcat(fname, install_script);
1696
1697 if (logfile)
1698 fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
1699
1700 tempname = tmpnam(NULL);
1701
1702 if (!freopen(tempname, "a", stderr))
1703 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
1704 if (!freopen(tempname, "a", stdout))
1705 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
1706/*
1707 if (0 != setvbuf(stdout, NULL, _IONBF, 0))
1708 MessageBox(GetFocus(), "setvbuf stdout", NULL, MB_OK);
1709*/
1710 hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
1711
1712 argv[0] = fname;
1713
1714 hPython = LoadLibrary(pythondll);
1715 if (hPython) {
1716 int result;
1717 result = run_installscript(hPython, fname, 2, argv);
1718 if (-1 == result) {
1719 fprintf(stderr, "*** run_installscript: internal error 0x%X ***\n", result);
1720 }
1721 FreeLibrary(hPython);
1722 } else {
1723 fprintf(stderr, "*** Could not load Python ***");
1724 }
1725 fflush(stderr);
1726 fflush(stdout);
1727
1728 fp = fopen(tempname, "rb");
1729 n = fread(buffer, 1, sizeof(buffer), fp);
1730 fclose(fp);
1731 remove(tempname);
1732
1733 buffer[n] = '\0';
1734
1735 SetDlgItemText(hwnd, IDC_INFO, buffer);
1736 SetDlgItemText(hwnd, IDC_TITLE,
1737 "Postinstall script finished.\n"
1738 "Click the Finish button to exit the Setup wizard.");
1739
1740 SetCursor(hCursor);
1741 CloseLogfile();
1742 }
1743
1744 return TRUE;
1745
1746 case WM_NOTIFY:
1747 lpnm = (LPNMHDR) lParam;
1748
1749 switch (lpnm->code) {
1750 case PSN_SETACTIVE: /* Enable the Finish button */
1751 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH);
1752 break;
1753
1754 case PSN_WIZNEXT:
1755 break;
1756
1757 case PSN_WIZFINISH:
1758 break;
1759
1760 case PSN_RESET:
1761 break;
1762
1763 default:
1764 break;
1765 }
1766 }
1767 return 0;
1768}
1769
1770void RunWizard(HWND hwnd)
1771{
1772 PROPSHEETPAGE psp = {0};
1773 HPROPSHEETPAGE ahpsp[4] = {0};
1774 PROPSHEETHEADER psh = {0};
1775
1776 /* Display module information */
1777 psp.dwSize = sizeof(psp);
1778 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
1779 psp.hInstance = GetModuleHandle (NULL);
1780 psp.lParam = 0;
1781 psp.pfnDlgProc = IntroDlgProc;
1782 psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO);
1783
1784 ahpsp[0] = CreatePropertySheetPage(&psp);
1785
1786 /* Select python version to use */
1787 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
1788 psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTPYTHON);
1789 psp.pfnDlgProc = SelectPythonDlgProc;
1790
1791 ahpsp[1] = CreatePropertySheetPage(&psp);
1792
1793 /* Install the files */
1794 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
1795 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFILES);
1796 psp.pfnDlgProc = InstallFilesDlgProc;
1797
1798 ahpsp[2] = CreatePropertySheetPage(&psp);
1799
1800 /* Show success or failure */
1801 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
1802 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHED);
1803 psp.pfnDlgProc = FinishedDlgProc;
1804
1805 ahpsp[3] = CreatePropertySheetPage(&psp);
1806
1807 /* Create the property sheet */
1808 psh.dwSize = sizeof(psh);
1809 psh.hInstance = GetModuleHandle(NULL);
1810 psh.hwndParent = hwnd;
1811 psh.phpage = ahpsp;
1812 psh.dwFlags = PSH_WIZARD/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
1813 psh.pszbmWatermark = NULL;
1814 psh.pszbmHeader = NULL;
1815 psh.nStartPage = 0;
1816 psh.nPages = 4;
1817
1818 PropertySheet(&psh);
1819}
1820
1821int DoInstall(void)
1822{
1823 char ini_buffer[4096];
1824
1825 /* Read installation information */
1826 GetPrivateProfileString("Setup", "title", "", ini_buffer,
1827 sizeof(ini_buffer), ini_file);
1828 unescape(title, ini_buffer, sizeof(title));
1829
1830 GetPrivateProfileString("Setup", "info", "", ini_buffer,
1831 sizeof(ini_buffer), ini_file);
1832 unescape(info, ini_buffer, sizeof(info));
1833
1834 GetPrivateProfileString("Setup", "build_info", "", build_info,
1835 sizeof(build_info), ini_file);
1836
1837 pyc_compile = GetPrivateProfileInt("Setup", "target_compile", 1,
1838 ini_file);
1839 pyo_compile = GetPrivateProfileInt("Setup", "target_optimize", 1,
1840 ini_file);
1841
1842 GetPrivateProfileString("Setup", "target_version", "",
1843 target_version, sizeof(target_version),
1844 ini_file);
1845
1846 GetPrivateProfileString("metadata", "name", "",
1847 meta_name, sizeof(meta_name),
1848 ini_file);
1849
1850 GetPrivateProfileString("Setup", "install_script", "",
1851 install_script, sizeof(install_script),
1852 ini_file);
1853
1854
1855 hwndMain = CreateBackground(title);
1856
1857 RunWizard(hwndMain);
1858
1859 /* Clean up */
1860 UnmapViewOfFile(arc_data);
1861 if (ini_file)
1862 DeleteFile(ini_file);
1863
1864 if (hBitmap)
1865 DeleteObject(hBitmap);
1866
1867 return 0;
1868}
1869
1870/*********************** uninstall section ******************************/
1871
1872static int compare(const void *p1, const void *p2)
1873{
1874 return strcmp(*(char **)p2, *(char **)p1);
1875}
1876
1877/*
1878 * Commit suicide (remove the uninstaller itself).
1879 *
1880 * Create a batch file to first remove the uninstaller
1881 * (will succeed after it has finished), then the batch file itself.
1882 *
1883 * This technique has been demonstrated by Jeff Richter,
1884 * MSJ 1/1996
1885 */
1886void remove_exe(void)
1887{
1888 char exename[_MAX_PATH];
1889 char batname[_MAX_PATH];
1890 FILE *fp;
1891 STARTUPINFO si;
1892 PROCESS_INFORMATION pi;
1893
1894 GetModuleFileName(NULL, exename, sizeof(exename));
1895 sprintf(batname, "%s.bat", exename);
1896 fp = fopen(batname, "w");
1897 fprintf(fp, ":Repeat\n");
1898 fprintf(fp, "del \"%s\"\n", exename);
1899 fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
1900 fprintf(fp, "del \"%s\"\n", batname);
1901 fclose(fp);
1902
1903 ZeroMemory(&si, sizeof(si));
1904 si.cb = sizeof(si);
1905 si.dwFlags = STARTF_USESHOWWINDOW;
1906 si.wShowWindow = SW_HIDE;
1907 if (CreateProcess(NULL,
1908 batname,
1909 NULL,
1910 NULL,
1911 FALSE,
1912 CREATE_SUSPENDED | IDLE_PRIORITY_CLASS,
1913 NULL,
1914 "\\",
1915 &si,
1916 &pi)) {
1917 SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE);
1918 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
1919 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
1920 CloseHandle(pi.hProcess);
1921 ResumeThread(pi.hThread);
1922 CloseHandle(pi.hThread);
1923 }
1924}
1925
1926void DeleteRegistryKey(char *string)
1927{
1928 char *keyname;
1929 char *subkeyname;
1930 char *delim;
1931 HKEY hKey;
1932 long result;
1933 char *line;
1934
1935 line = strdup(string); /* so we can change it */
1936
1937 keyname = strchr(line, '[');
1938 if (!keyname)
1939 return;
1940 ++keyname;
1941
1942 subkeyname = strchr(keyname, ']');
1943 if (!subkeyname)
1944 return;
1945 *subkeyname++='\0';
1946 delim = strchr(subkeyname, '\n');
1947 if (delim)
1948 *delim = '\0';
1949
1950 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1951 keyname,
1952 0,
1953 KEY_WRITE,
1954 &hKey);
1955
1956 if (result != ERROR_SUCCESS)
1957 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
1958 else {
1959 result = RegDeleteKey(hKey, subkeyname);
1960 if (result != ERROR_SUCCESS)
1961 MessageBox(GetFocus(), string, "Could not delete key", MB_OK);
1962 RegCloseKey(hKey);
1963 }
1964 free(line);
1965}
1966
1967void DeleteRegistryValue(char *string)
1968{
1969 char *keyname;
1970 char *valuename;
1971 char *value;
1972 HKEY hKey;
1973 long result;
1974 char *line;
1975
1976 line = strdup(string); /* so we can change it */
1977
1978/* Format is 'Reg DB Value: [key]name=value' */
1979 keyname = strchr(line, '[');
1980 if (!keyname)
1981 return;
1982 ++keyname;
1983 valuename = strchr(keyname, ']');
1984 if (!valuename)
1985 return;
1986 *valuename++ = '\0';
1987 value = strchr(valuename, '=');
1988 if (!value)
1989 return;
1990
1991 *value++ = '\0';
1992
1993 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1994 keyname,
1995 0,
1996 KEY_WRITE,
1997 &hKey);
1998 if (result != ERROR_SUCCESS)
1999 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2000 else {
2001 result = RegDeleteValue(hKey, valuename);
2002 if (result != ERROR_SUCCESS)
2003 MessageBox(GetFocus(), string, "Could not delete value", MB_OK);
2004 RegCloseKey(hKey);
2005 }
2006 free(line);
2007}
2008
2009BOOL MyDeleteFile(char *line)
2010{
2011 char *pathname = strchr(line, ':');
2012 if (!pathname)
2013 return FALSE;
2014 ++pathname;
2015 while (isspace(*pathname))
2016 ++pathname;
2017 return DeleteFile(pathname);
2018}
2019
2020BOOL MyRemoveDirectory(char *line)
2021{
2022 char *pathname = strchr(line, ':');
2023 if (!pathname)
2024 return FALSE;
2025 ++pathname;
2026 while (isspace(*pathname))
2027 ++pathname;
2028 return RemoveDirectory(pathname);
2029}
2030
2031BOOL Run_RemoveScript(char *line)
2032{
2033 char *dllname;
2034 char *scriptname;
2035 static char lastscript[MAX_PATH];
2036
2037/* Format is 'Run Scripts: [pythondll]scriptname' */
2038/* XXX Currently, pythondll carries no path!!! */
2039 dllname = strchr(line, '[');
2040 if (!dllname)
2041 return FALSE;
2042 ++dllname;
2043 scriptname = strchr(dllname, ']');
2044 if (!scriptname)
2045 return FALSE;
2046 *scriptname++ = '\0';
2047 /* this function may be called more than one time with the same
2048 script, only run it one time */
2049 if (strcmp(lastscript, scriptname)) {
2050 HINSTANCE hPython;
2051 char *argv[3] = {NULL, "-remove", NULL};
2052 char buffer[4096];
2053 FILE *fp;
2054 char *tempname;
2055 int n;
2056
2057 argv[0] = scriptname;
2058
2059 tempname = tmpnam(NULL);
2060
2061 if (!freopen(tempname, "a", stderr))
2062 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
2063 if (!freopen(tempname, "a", stdout))
2064 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
2065
2066 hPython = LoadLibrary(dllname);
2067 if (hPython) {
2068 if (0x80000000 == run_installscript(hPython, scriptname, 2, argv))
2069 fprintf(stderr, "*** Could not load Python ***");
2070 FreeLibrary(hPython);
2071 }
2072
2073 fflush(stderr);
2074 fflush(stdout);
2075
2076 fp = fopen(tempname, "rb");
2077 n = fread(buffer, 1, sizeof(buffer), fp);
2078 fclose(fp);
2079 remove(tempname);
2080
2081 buffer[n] = '\0';
2082 if (buffer[0])
2083 MessageBox(GetFocus(), buffer, "uninstall-script", MB_OK);
2084
2085 strcpy(lastscript, scriptname);
2086 }
2087 return TRUE;
2088}
2089
2090int DoUninstall(int argc, char **argv)
2091{
2092 FILE *logfile;
2093 char buffer[4096];
2094 int nLines = 0;
2095 int i;
2096 char *cp;
2097 int nFiles = 0;
2098 int nDirs = 0;
2099 int nErrors = 0;
2100 char **lines;
2101 int lines_buffer_size = 10;
2102
2103 if (argc != 3) {
2104 MessageBox(NULL,
2105 "Wrong number of args",
2106 NULL,
2107 MB_OK);
2108 return 1; /* Error */
2109 }
2110 if (strcmp(argv[1], "-u")) {
2111 MessageBox(NULL,
2112 "2. arg is not -u",
2113 NULL,
2114 MB_OK);
2115 return 1; /* Error */
2116 }
2117
2118 {
2119 DWORD result;
2120 HKEY hKey;
2121 static char KeyName[] =
2122 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
2123
2124 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2125 KeyName,
2126 0,
2127 KEY_CREATE_SUB_KEY,
2128 &hKey);
2129 if (result == ERROR_ACCESS_DENIED) {
2130 MessageBox(GetFocus(),
2131 "You do not seem to have sufficient access rights\n"
2132 "on this machine to uninstall this software",
2133 NULL,
2134 MB_OK | MB_ICONSTOP);
2135 return 1; /* Error */
2136 }
2137 RegCloseKey(hKey);
2138 }
2139
2140 logfile = fopen(argv[2], "r");
2141 if (!logfile) {
2142 MessageBox(NULL,
2143 "could not open logfile",
2144 NULL,
2145 MB_OK);
2146 return 1; /* Error */
2147 }
2148
2149 lines = (char **)malloc(sizeof(char *) * lines_buffer_size);
2150 if (!lines)
2151 return SystemError(0, "Out of memory");
2152
2153 /* Read the whole logfile, realloacting the buffer */
2154 while (fgets(buffer, sizeof(buffer), logfile)) {
2155 int len = strlen(buffer);
2156 /* remove trailing white space */
2157 while (isspace(buffer[len-1]))
2158 len -= 1;
2159 buffer[len] = '\0';
2160 lines[nLines++] = strdup(buffer);
2161 if (nLines >= lines_buffer_size) {
2162 lines_buffer_size += 10;
2163 lines = (char **)realloc(lines,
2164 sizeof(char *) * lines_buffer_size);
2165 if (!lines)
2166 return SystemError(0, "Out of memory");
2167 }
2168 }
2169 fclose(logfile);
2170
2171 /* Sort all the lines, so that highest 3-digit codes are first */
2172 qsort(&lines[0], nLines, sizeof(char *),
2173 compare);
2174
2175 if (IDYES != MessageBox(NULL,
2176 "Are you sure you want to remove\n"
2177 "this package from your computer?",
2178 "Please confirm",
2179 MB_YESNO | MB_ICONQUESTION))
2180 return 0;
2181
2182 cp = "";
2183 for (i = 0; i < nLines; ++i) {
2184 /* Ignore duplicate lines */
2185 if (strcmp(cp, lines[i])) {
2186 int ign;
2187 cp = lines[i];
2188 /* Parse the lines */
2189 if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
2190 if (MyRemoveDirectory(cp))
2191 ++nDirs;
2192 else {
2193 int code = GetLastError();
2194 if (code != 2 && code != 3) { /* file or path not found */
2195 ++nErrors;
2196 }
2197 }
2198 } else if (2 == sscanf(cp, "%d File Copy: %s", &ign, &buffer)) {
2199 if (MyDeleteFile(cp))
2200 ++nFiles;
2201 else {
2202 int code = GetLastError();
2203 if (code != 2 && code != 3) { /* file or path not found */
2204 ++nErrors;
2205 }
2206 }
2207 } else if (2 == sscanf(cp, "%d File Overwrite: %s", &ign, &buffer)) {
2208 if (MyDeleteFile(cp))
2209 ++nFiles;
2210 else {
2211 int code = GetLastError();
2212 if (code != 2 && code != 3) { /* file or path not found */
2213 ++nErrors;
2214 }
2215 }
2216 } else if (2 == sscanf(cp, "%d Reg DB Key: %s", &ign, &buffer)) {
2217 DeleteRegistryKey(cp);
2218 } else if (2 == sscanf(cp, "%d Reg DB Value: %s", &ign, &buffer)) {
2219 DeleteRegistryValue(cp);
2220 } else if (2 == sscanf(cp, "%d Run Script: %s", &ign, &buffer)) {
2221 Run_RemoveScript(cp);
2222 }
2223 }
2224 }
2225
2226 if (DeleteFile(argv[2])) {
2227 ++nFiles;
2228 } else {
2229 ++nErrors;
2230 SystemError(GetLastError(), argv[2]);
2231 }
2232 if (nErrors)
2233 wsprintf(buffer,
2234 "%d files and %d directories removed\n"
2235 "%d files or directories could not be removed",
2236 nFiles, nDirs, nErrors);
2237 else
2238 wsprintf(buffer, "%d files and %d directories removed",
2239 nFiles, nDirs);
2240 MessageBox(NULL, buffer, "Uninstall Finished!",
2241 MB_OK | MB_ICONINFORMATION);
2242 remove_exe();
2243 return 0;
2244}
2245
2246int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
2247 LPSTR lpszCmdLine, INT nCmdShow)
2248{
2249 extern int __argc;
2250 extern char **__argv;
2251 char *basename;
2252
2253 GetModuleFileName(NULL, modulename, sizeof(modulename));
2254
2255 /* Map the executable file to memory */
2256 arc_data = MapExistingFile(modulename, &arc_size);
2257 if (!arc_data) {
2258 SystemError(GetLastError(), "Could not open archive");
2259 return 1;
2260 }
2261
2262 /* OK. So this program can act as installer (self-extracting
2263 * zip-file, or as uninstaller when started with '-u logfile'
2264 * command line flags.
2265 *
2266 * The installer is usually started without command line flags,
2267 * and the uninstaller is usually started with the '-u logfile'
2268 * flag. What to do if some innocent user double-clicks the
2269 * exe-file?
2270 * The following implements a defensive strategy...
2271 */
2272
2273 /* Try to extract the configuration data into a temporary file */
2274 ini_file = ExtractIniFile(arc_data, arc_size, &exe_size);
2275
2276 if (ini_file)
2277 return DoInstall();
2278
2279 if (!ini_file && __argc > 1) {
2280 return DoUninstall(__argc, __argv);
2281 }
2282
2283
2284 basename = strrchr(modulename, '\\');
2285 if (basename)
2286 ++basename;
2287
2288 /* Last guess about the purpose of this program */
2289 if (basename && (0 == strncmp(basename, "Remove", 6)))
2290 SystemError(0, "This program is normally started by windows");
2291 else
2292 SystemError(0, "Setup program invalid or damaged");
2293 return 1;
2294}