Fixed bug in fileConfig() which failed to clear logging._handlerList
[python.git] / PC / bdist_wininst / install.c
blob0ce2371a771d8dedde2df300fd7828a2ac94233f
1 /*
2 IMPORTANT NOTE: IF THIS FILE IS CHANGED, WININST-6.EXE MUST BE RECOMPILED
3 WITH THE MSVC6 WININST.DSW WORKSPACE FILE MANUALLY, AND WININST-7.1.EXE MUST
4 BE RECOMPILED WITH THE MSVC 2003.NET WININST-7.1.VCPROJ FILE MANUALLY.
6 IF CHANGES TO THIS FILE ARE CHECKED INTO PYTHON CVS, THE RECOMPILED BINARIES
7 MUST BE CHECKED IN AS WELL!
8 */
11 * Written by Thomas Heller, May 2000
13 * $Id$
17 * Windows Installer program for distutils.
19 * (a kind of self-extracting zip-file)
21 * At runtime, the exefile has appended:
22 * - compressed setup-data in ini-format, containing the following sections:
23 * [metadata]
24 * author=Greg Ward
25 * author_email=gward@python.net
26 * description=Python Distribution Utilities
27 * licence=Python
28 * name=Distutils
29 * url=http://www.python.org/sigs/distutils-sig/
30 * version=0.9pre
32 * [Setup]
33 * info= text to be displayed in the edit-box
34 * title= to be displayed by this program
35 * target_version = if present, python version required
36 * pyc_compile = if 0, do not compile py to pyc
37 * pyo_compile = if 0, do not compile py to pyo
39 * - a struct meta_data_hdr, describing the above
40 * - a zip-file, containing the modules to be installed.
41 * for the format see http://www.pkware.com/appnote.html
43 * What does this program do?
44 * - the setup-data is uncompressed and written to a temporary file.
45 * - setup-data is queried with GetPrivateProfile... calls
46 * - [metadata] - info is displayed in the dialog box
47 * - The registry is searched for installations of python
48 * - The user can select the python version to use.
49 * - The python-installation directory (sys.prefix) is displayed
50 * - When the start-button is pressed, files from the zip-archive
51 * are extracted to the file system. All .py filenames are stored
52 * in a list.
55 * Includes now an uninstaller.
59 * To Do:
61 * display some explanation when no python version is found
62 * instead showing the user an empty listbox to select something from.
64 * Finish the code so that we can use other python installations
65 * additionaly to those found in the registry,
66 * and then #define USE_OTHER_PYTHON_VERSIONS
68 * - install a help-button, which will display something meaningful
69 * to the poor user.
70 * text to the user
71 * - should there be a possibility to display a README file
72 * before starting the installation (if one is present in the archive)
73 * - more comments about what the code does(?)
75 * - evolve this into a full blown installer (???)
78 #include <windows.h>
79 #include <commctrl.h>
80 #include <imagehlp.h>
81 #include <objbase.h>
82 #include <shlobj.h>
83 #include <objidl.h>
84 #include "resource.h"
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <stdarg.h>
89 #include <string.h>
90 #include <time.h>
91 #include <sys/types.h>
92 #include <sys/stat.h>
93 #include <malloc.h>
94 #include <io.h>
95 #include <fcntl.h>
97 #include "archive.h"
99 /* Only for debugging!
100 static int dprintf(char *fmt, ...)
102 char Buffer[4096];
103 va_list marker;
104 int result;
106 va_start(marker, fmt);
107 result = wvsprintf(Buffer, fmt, marker);
108 OutputDebugString(Buffer);
109 return result;
113 /* Bah: global variables */
114 FILE *logfile;
116 char modulename[MAX_PATH];
118 HWND hwndMain;
119 HWND hDialog;
121 char *ini_file; /* Full pathname of ini-file */
122 /* From ini-file */
123 char info[4096]; /* [Setup] info= */
124 char title[80]; /* [Setup] title=, contains package name
125 including version: "Distutils-1.0.1" */
126 char target_version[10]; /* [Setup] target_version=, required python
127 version or empty string */
128 char build_info[80]; /* [Setup] build_info=, distutils version
129 and build date */
131 char meta_name[80]; /* package name without version like
132 'Distutils' */
133 char install_script[MAX_PATH];
134 char *pre_install_script; /* run before we install a single file */
137 int py_major, py_minor; /* Python version selected for installation */
139 char *arc_data; /* memory mapped archive */
140 DWORD arc_size; /* number of bytes in archive */
141 int exe_size; /* number of bytes for exe-file portion */
142 char python_dir[MAX_PATH];
143 char pythondll[MAX_PATH];
144 BOOL pyc_compile, pyo_compile;
145 /* Either HKLM or HKCU, depending on where Python itself is registered, and
146 the permissions of the current user. */
147 HKEY hkey_root = (HKEY)-1;
149 BOOL success; /* Installation successfull? */
150 char *failure_reason = NULL;
152 HANDLE hBitmap;
153 char *bitmap_bytes;
156 #define WM_NUMFILES WM_USER+1
157 /* wParam: 0, lParam: total number of files */
158 #define WM_NEXTFILE WM_USER+2
159 /* wParam: number of this file */
160 /* lParam: points to pathname */
162 static BOOL notify(int code, char *fmt, ...);
164 /* Note: If scheme.prefix is nonempty, it must end with a '\'! */
165 /* Note: purelib must be the FIRST entry! */
166 SCHEME old_scheme[] = {
167 { "PURELIB", "" },
168 { "PLATLIB", "" },
169 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
170 { "SCRIPTS", "Scripts\\" },
171 { "DATA", "" },
172 { NULL, NULL },
175 SCHEME new_scheme[] = {
176 { "PURELIB", "Lib\\site-packages\\" },
177 { "PLATLIB", "Lib\\site-packages\\" },
178 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
179 { "SCRIPTS", "Scripts\\" },
180 { "DATA", "" },
181 { NULL, NULL },
184 static void unescape(char *dst, char *src, unsigned size)
186 char *eon;
187 char ch;
189 while (src && *src && (size > 2)) {
190 if (*src == '\\') {
191 switch (*++src) {
192 case 'n':
193 ++src;
194 *dst++ = '\r';
195 *dst++ = '\n';
196 size -= 2;
197 break;
198 case 'r':
199 ++src;
200 *dst++ = '\r';
201 --size;
202 break;
203 case '0': case '1': case '2': case '3':
204 ch = (char)strtol(src, &eon, 8);
205 if (ch == '\n') {
206 *dst++ = '\r';
207 --size;
209 *dst++ = ch;
210 --size;
211 src = eon;
213 } else {
214 *dst++ = *src++;
215 --size;
218 *dst = '\0';
221 static struct tagFile {
222 char *path;
223 struct tagFile *next;
224 } *file_list = NULL;
226 static void set_failure_reason(char *reason)
228 if (failure_reason)
229 free(failure_reason);
230 failure_reason = strdup(reason);
231 success = FALSE;
233 static char *get_failure_reason()
235 if (!failure_reason)
236 return "Installation failed.";
237 return failure_reason;
240 static void add_to_filelist(char *path)
242 struct tagFile *p;
243 p = (struct tagFile *)malloc(sizeof(struct tagFile));
244 p->path = strdup(path);
245 p->next = file_list;
246 file_list = p;
249 static int do_compile_files(int (__cdecl * PyRun_SimpleString)(char *),
250 int optimize)
252 struct tagFile *p;
253 int total, n;
254 char Buffer[MAX_PATH + 64];
255 int errors = 0;
257 total = 0;
258 p = file_list;
259 while (p) {
260 ++total;
261 p = p->next;
263 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETRANGE, 0,
264 MAKELPARAM(0, total));
265 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETPOS, 0, 0);
267 n = 0;
268 p = file_list;
269 while (p) {
270 ++n;
271 wsprintf(Buffer,
272 "import py_compile; py_compile.compile (r'%s')",
273 p->path);
274 if (PyRun_SimpleString(Buffer)) {
275 ++errors;
277 /* We send the notification even if the files could not
278 * be created so that the uninstaller will remove them
279 * in case they are created later.
281 wsprintf(Buffer, "%s%c", p->path, optimize ? 'o' : 'c');
282 notify(FILE_CREATED, Buffer);
284 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETPOS, n, 0);
285 SetDlgItemText(hDialog, IDC_INFO, p->path);
286 p = p->next;
288 return errors;
291 #define DECLPROC(dll, result, name, args)\
292 typedef result (*__PROC__##name) args;\
293 result (*name)args = (__PROC__##name)GetProcAddress(dll, #name)
296 #define DECLVAR(dll, type, name)\
297 type *name = (type*)GetProcAddress(dll, #name)
299 typedef void PyObject;
303 * Returns number of files which failed to compile,
304 * -1 if python could not be loaded at all
306 static int compile_filelist(HINSTANCE hPython, BOOL optimize_flag)
308 DECLPROC(hPython, void, Py_Initialize, (void));
309 DECLPROC(hPython, void, Py_SetProgramName, (char *));
310 DECLPROC(hPython, void, Py_Finalize, (void));
311 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
312 DECLPROC(hPython, PyObject *, PySys_GetObject, (char *));
313 DECLVAR(hPython, int, Py_OptimizeFlag);
315 int errors = 0;
316 struct tagFile *p = file_list;
318 if (!p)
319 return 0;
321 if (!Py_Initialize || !Py_SetProgramName || !Py_Finalize)
322 return -1;
324 if (!PyRun_SimpleString || !PySys_GetObject || !Py_OptimizeFlag)
325 return -1;
327 *Py_OptimizeFlag = optimize_flag ? 1 : 0;
328 Py_SetProgramName(modulename);
329 Py_Initialize();
331 errors += do_compile_files(PyRun_SimpleString, optimize_flag);
332 Py_Finalize();
334 return errors;
337 typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
339 struct PyMethodDef {
340 char *ml_name;
341 PyCFunction ml_meth;
342 int ml_flags;
343 char *ml_doc;
345 typedef struct PyMethodDef PyMethodDef;
347 void *(*g_Py_BuildValue)(char *, ...);
348 int (*g_PyArg_ParseTuple)(PyObject *, char *, ...);
350 PyObject *g_PyExc_ValueError;
351 PyObject *g_PyExc_OSError;
353 PyObject *(*g_PyErr_Format)(PyObject *, char *, ...);
355 #define DEF_CSIDL(name) { name, #name }
357 struct {
358 int nFolder;
359 char *name;
360 } csidl_names[] = {
361 /* Startup menu for all users.
362 NT only */
363 DEF_CSIDL(CSIDL_COMMON_STARTMENU),
364 /* Startup menu. */
365 DEF_CSIDL(CSIDL_STARTMENU),
367 /* DEF_CSIDL(CSIDL_COMMON_APPDATA), */
368 /* DEF_CSIDL(CSIDL_LOCAL_APPDATA), */
369 /* Repository for application-specific data.
370 Needs Internet Explorer 4.0 */
371 DEF_CSIDL(CSIDL_APPDATA),
373 /* The desktop for all users.
374 NT only */
375 DEF_CSIDL(CSIDL_COMMON_DESKTOPDIRECTORY),
376 /* The desktop. */
377 DEF_CSIDL(CSIDL_DESKTOPDIRECTORY),
379 /* Startup folder for all users.
380 NT only */
381 DEF_CSIDL(CSIDL_COMMON_STARTUP),
382 /* Startup folder. */
383 DEF_CSIDL(CSIDL_STARTUP),
385 /* Programs item in the start menu for all users.
386 NT only */
387 DEF_CSIDL(CSIDL_COMMON_PROGRAMS),
388 /* Program item in the user's start menu. */
389 DEF_CSIDL(CSIDL_PROGRAMS),
391 /* DEF_CSIDL(CSIDL_PROGRAM_FILES_COMMON), */
392 /* DEF_CSIDL(CSIDL_PROGRAM_FILES), */
394 /* Virtual folder containing fonts. */
395 DEF_CSIDL(CSIDL_FONTS),
398 #define DIM(a) (sizeof(a) / sizeof((a)[0]))
400 static PyObject *FileCreated(PyObject *self, PyObject *args)
402 char *path;
403 if (!g_PyArg_ParseTuple(args, "s", &path))
404 return NULL;
405 notify(FILE_CREATED, path);
406 return g_Py_BuildValue("");
409 static PyObject *DirectoryCreated(PyObject *self, PyObject *args)
411 char *path;
412 if (!g_PyArg_ParseTuple(args, "s", &path))
413 return NULL;
414 notify(DIR_CREATED, path);
415 return g_Py_BuildValue("");
418 static PyObject *GetSpecialFolderPath(PyObject *self, PyObject *args)
420 char *name;
421 char lpszPath[MAX_PATH];
422 int i;
423 static HRESULT (WINAPI *My_SHGetSpecialFolderPath)(HWND hwnd,
424 LPTSTR lpszPath,
425 int nFolder,
426 BOOL fCreate);
428 if (!My_SHGetSpecialFolderPath) {
429 HINSTANCE hLib = LoadLibrary("shell32.dll");
430 if (!hLib) {
431 g_PyErr_Format(g_PyExc_OSError,
432 "function not available");
433 return NULL;
435 My_SHGetSpecialFolderPath = (BOOL (WINAPI *)(HWND, LPTSTR,
436 int, BOOL))
437 GetProcAddress(hLib,
438 "SHGetSpecialFolderPathA");
441 if (!g_PyArg_ParseTuple(args, "s", &name))
442 return NULL;
444 if (!My_SHGetSpecialFolderPath) {
445 g_PyErr_Format(g_PyExc_OSError, "function not available");
446 return NULL;
449 for (i = 0; i < DIM(csidl_names); ++i) {
450 if (0 == strcmpi(csidl_names[i].name, name)) {
451 int nFolder;
452 nFolder = csidl_names[i].nFolder;
453 if (My_SHGetSpecialFolderPath(NULL, lpszPath,
454 nFolder, 0))
455 return g_Py_BuildValue("s", lpszPath);
456 else {
457 g_PyErr_Format(g_PyExc_OSError,
458 "no such folder (%s)", name);
459 return NULL;
464 g_PyErr_Format(g_PyExc_ValueError, "unknown CSIDL (%s)", name);
465 return NULL;
468 static PyObject *CreateShortcut(PyObject *self, PyObject *args)
470 char *path; /* path and filename */
471 char *description;
472 char *filename;
474 char *arguments = NULL;
475 char *iconpath = NULL;
476 int iconindex = 0;
477 char *workdir = NULL;
479 WCHAR wszFilename[MAX_PATH];
481 IShellLink *ps1 = NULL;
482 IPersistFile *pPf = NULL;
484 HRESULT hr;
486 hr = CoInitialize(NULL);
487 if (FAILED(hr)) {
488 g_PyErr_Format(g_PyExc_OSError,
489 "CoInitialize failed, error 0x%x", hr);
490 goto error;
493 if (!g_PyArg_ParseTuple(args, "sss|sssi",
494 &path, &description, &filename,
495 &arguments, &workdir, &iconpath, &iconindex))
496 return NULL;
498 hr = CoCreateInstance(&CLSID_ShellLink,
499 NULL,
500 CLSCTX_INPROC_SERVER,
501 &IID_IShellLink,
502 &ps1);
503 if (FAILED(hr)) {
504 g_PyErr_Format(g_PyExc_OSError,
505 "CoCreateInstance failed, error 0x%x", hr);
506 goto error;
509 hr = ps1->lpVtbl->QueryInterface(ps1, &IID_IPersistFile,
510 (void **)&pPf);
511 if (FAILED(hr)) {
512 g_PyErr_Format(g_PyExc_OSError,
513 "QueryInterface(IPersistFile) error 0x%x", hr);
514 goto error;
518 hr = ps1->lpVtbl->SetPath(ps1, path);
519 if (FAILED(hr)) {
520 g_PyErr_Format(g_PyExc_OSError,
521 "SetPath() failed, error 0x%x", hr);
522 goto error;
525 hr = ps1->lpVtbl->SetDescription(ps1, description);
526 if (FAILED(hr)) {
527 g_PyErr_Format(g_PyExc_OSError,
528 "SetDescription() failed, error 0x%x", hr);
529 goto error;
532 if (arguments) {
533 hr = ps1->lpVtbl->SetArguments(ps1, arguments);
534 if (FAILED(hr)) {
535 g_PyErr_Format(g_PyExc_OSError,
536 "SetArguments() error 0x%x", hr);
537 goto error;
541 if (iconpath) {
542 hr = ps1->lpVtbl->SetIconLocation(ps1, iconpath, iconindex);
543 if (FAILED(hr)) {
544 g_PyErr_Format(g_PyExc_OSError,
545 "SetIconLocation() error 0x%x", hr);
546 goto error;
550 if (workdir) {
551 hr = ps1->lpVtbl->SetWorkingDirectory(ps1, workdir);
552 if (FAILED(hr)) {
553 g_PyErr_Format(g_PyExc_OSError,
554 "SetWorkingDirectory() error 0x%x", hr);
555 goto error;
559 MultiByteToWideChar(CP_ACP, 0,
560 filename, -1,
561 wszFilename, MAX_PATH);
563 hr = pPf->lpVtbl->Save(pPf, wszFilename, TRUE);
564 if (FAILED(hr)) {
565 g_PyErr_Format(g_PyExc_OSError,
566 "Failed to create shortcut '%s' - error 0x%x", filename, hr);
567 goto error;
570 pPf->lpVtbl->Release(pPf);
571 ps1->lpVtbl->Release(ps1);
572 CoUninitialize();
573 return g_Py_BuildValue("");
575 error:
576 if (pPf)
577 pPf->lpVtbl->Release(pPf);
579 if (ps1)
580 ps1->lpVtbl->Release(ps1);
582 CoUninitialize();
584 return NULL;
587 static PyObject *PyMessageBox(PyObject *self, PyObject *args)
589 int rc;
590 char *text, *caption;
591 int flags;
592 if (!g_PyArg_ParseTuple(args, "ssi", &text, &caption, &flags))
593 return NULL;
594 rc = MessageBox(GetFocus(), text, caption, flags);
595 return g_Py_BuildValue("i", rc);
598 static PyObject *GetRootHKey(PyObject *self)
600 return g_Py_BuildValue("l", hkey_root);
603 #define METH_VARARGS 0x0001
604 #define METH_NOARGS 0x0004
605 typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
607 PyMethodDef meth[] = {
608 {"create_shortcut", CreateShortcut, METH_VARARGS, NULL},
609 {"get_special_folder_path", GetSpecialFolderPath, METH_VARARGS, NULL},
610 {"get_root_hkey", (PyCFunction)GetRootHKey, METH_NOARGS, NULL},
611 {"file_created", FileCreated, METH_VARARGS, NULL},
612 {"directory_created", DirectoryCreated, METH_VARARGS, NULL},
613 {"message_box", PyMessageBox, METH_VARARGS, NULL},
616 static HINSTANCE LoadPythonDll(char *fname)
618 char fullpath[_MAX_PATH];
619 LONG size = sizeof(fullpath);
620 char subkey_name[80];
621 char buffer[260 + 12];
622 HINSTANCE h;
624 /* make sure PYTHONHOME is set, to that sys.path is initialized correctly */
625 wsprintf(buffer, "PYTHONHOME=%s", python_dir);
626 _putenv(buffer);
627 h = LoadLibrary(fname);
628 if (h)
629 return h;
630 wsprintf(subkey_name,
631 "SOFTWARE\\Python\\PythonCore\\%d.%d\\InstallPath",
632 py_major, py_minor);
633 if (ERROR_SUCCESS != RegQueryValue(HKEY_CURRENT_USER, subkey_name,
634 fullpath, &size))
635 return NULL;
636 strcat(fullpath, "\\");
637 strcat(fullpath, fname);
638 return LoadLibrary(fullpath);
641 static int prepare_script_environment(HINSTANCE hPython)
643 PyObject *mod;
644 DECLPROC(hPython, PyObject *, PyImport_ImportModule, (char *));
645 DECLPROC(hPython, int, PyObject_SetAttrString, (PyObject *, char *, PyObject *));
646 DECLPROC(hPython, PyObject *, PyObject_GetAttrString, (PyObject *, char *));
647 DECLPROC(hPython, PyObject *, PyCFunction_New, (PyMethodDef *, PyObject *));
648 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
649 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
650 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
651 if (!PyImport_ImportModule || !PyObject_GetAttrString ||
652 !PyObject_SetAttrString || !PyCFunction_New)
653 return 1;
654 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
655 return 1;
657 mod = PyImport_ImportModule("__builtin__");
658 if (mod) {
659 int i;
660 g_PyExc_ValueError = PyObject_GetAttrString(mod, "ValueError");
661 g_PyExc_OSError = PyObject_GetAttrString(mod, "OSError");
662 for (i = 0; i < DIM(meth); ++i) {
663 PyObject_SetAttrString(mod, meth[i].ml_name,
664 PyCFunction_New(&meth[i], NULL));
667 g_Py_BuildValue = Py_BuildValue;
668 g_PyArg_ParseTuple = PyArg_ParseTuple;
669 g_PyErr_Format = PyErr_Format;
671 return 0;
675 * This function returns one of the following error codes:
676 * 1 if the Python-dll does not export the functions we need
677 * 2 if no install-script is specified in pathname
678 * 3 if the install-script file could not be opened
679 * the return value of PyRun_SimpleString() otherwise,
680 * which is 0 if everything is ok, -1 if an exception had occurred
681 * in the install-script.
684 static int
685 run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
687 DECLPROC(hPython, void, Py_Initialize, (void));
688 DECLPROC(hPython, int, PySys_SetArgv, (int, char **));
689 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
690 DECLPROC(hPython, void, Py_Finalize, (void));
691 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
692 DECLPROC(hPython, PyObject *, PyCFunction_New,
693 (PyMethodDef *, PyObject *));
694 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
695 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
697 int result = 0;
698 int fh;
700 if (!Py_Initialize || !PySys_SetArgv
701 || !PyRun_SimpleString || !Py_Finalize)
702 return 1;
704 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
705 return 1;
707 if (!PyCFunction_New || !PyArg_ParseTuple || !PyErr_Format)
708 return 1;
710 if (pathname == NULL || pathname[0] == '\0')
711 return 2;
713 fh = open(pathname, _O_RDONLY);
714 if (-1 == fh) {
715 fprintf(stderr, "Could not open postinstall-script %s\n",
716 pathname);
717 return 3;
720 SetDlgItemText(hDialog, IDC_INFO, "Running Script...");
722 Py_Initialize();
724 prepare_script_environment(hPython);
725 PySys_SetArgv(argc, argv);
726 result = 3;
728 struct _stat statbuf;
729 if(0 == _fstat(fh, &statbuf)) {
730 char *script = alloca(statbuf.st_size + 5);
731 int n = read(fh, script, statbuf.st_size);
732 if (n > 0) {
733 script[n] = '\n';
734 script[n+1] = 0;
735 result = PyRun_SimpleString(script);
739 Py_Finalize();
741 close(fh);
743 return result;
746 static int do_run_simple_script(HINSTANCE hPython, char *script)
748 int rc;
749 DECLPROC(hPython, void, Py_Initialize, (void));
750 DECLPROC(hPython, void, Py_SetProgramName, (char *));
751 DECLPROC(hPython, void, Py_Finalize, (void));
752 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
753 DECLPROC(hPython, void, PyErr_Print, (void));
755 if (!Py_Initialize || !Py_SetProgramName || !Py_Finalize ||
756 !PyRun_SimpleString || !PyErr_Print)
757 return -1;
759 Py_SetProgramName(modulename);
760 Py_Initialize();
761 prepare_script_environment(hPython);
762 rc = PyRun_SimpleString(script);
763 if (rc)
764 PyErr_Print();
765 Py_Finalize();
766 return rc;
769 static int run_simple_script(char *script)
771 int rc;
772 char *tempname;
773 HINSTANCE hPython;
774 tempname = tempnam(NULL, NULL);
775 freopen(tempname, "a", stderr);
776 freopen(tempname, "a", stdout);
778 hPython = LoadPythonDll(pythondll);
779 if (!hPython) {
780 set_failure_reason("Can't load Python for pre-install script");
781 return -1;
783 rc = do_run_simple_script(hPython, script);
784 FreeLibrary(hPython);
785 fflush(stderr);
786 fclose(stderr);
787 fflush(stdout);
788 fclose(stdout);
789 /* We only care about the output when we fail. If the script works
790 OK, then we discard it
792 if (rc) {
793 int err_buf_size;
794 char *err_buf;
795 const char *prefix = "Running the pre-installation script failed\r\n";
796 int prefix_len = strlen(prefix);
797 FILE *fp = fopen(tempname, "rb");
798 fseek(fp, 0, SEEK_END);
799 err_buf_size = ftell(fp);
800 fseek(fp, 0, SEEK_SET);
801 err_buf = malloc(prefix_len + err_buf_size + 1);
802 if (err_buf) {
803 int n;
804 strcpy(err_buf, prefix);
805 n = fread(err_buf+prefix_len, 1, err_buf_size, fp);
806 err_buf[prefix_len+n] = '\0';
807 fclose(fp);
808 set_failure_reason(err_buf);
809 free(err_buf);
810 } else {
811 set_failure_reason("Out of memory!");
814 remove(tempname);
815 return rc;
819 static BOOL SystemError(int error, char *msg)
821 char Buffer[1024];
822 int n;
824 if (error) {
825 LPVOID lpMsgBuf;
826 FormatMessage(
827 FORMAT_MESSAGE_ALLOCATE_BUFFER |
828 FORMAT_MESSAGE_FROM_SYSTEM,
829 NULL,
830 error,
831 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
832 (LPSTR)&lpMsgBuf,
834 NULL
836 strncpy(Buffer, lpMsgBuf, sizeof(Buffer));
837 LocalFree(lpMsgBuf);
838 } else
839 Buffer[0] = '\0';
840 n = lstrlen(Buffer);
841 _snprintf(Buffer+n, sizeof(Buffer)-n, msg);
842 MessageBox(hwndMain, Buffer, "Runtime Error", MB_OK | MB_ICONSTOP);
843 return FALSE;
846 static BOOL notify (int code, char *fmt, ...)
848 char Buffer[1024];
849 va_list marker;
850 BOOL result = TRUE;
851 int a, b;
852 char *cp;
854 va_start(marker, fmt);
855 _vsnprintf(Buffer, sizeof(Buffer), fmt, marker);
857 switch (code) {
858 /* Questions */
859 case CAN_OVERWRITE:
860 break;
862 /* Information notification */
863 case DIR_CREATED:
864 if (logfile)
865 fprintf(logfile, "100 Made Dir: %s\n", fmt);
866 break;
868 case FILE_CREATED:
869 if (logfile)
870 fprintf(logfile, "200 File Copy: %s\n", fmt);
871 goto add_to_filelist_label;
872 break;
874 case FILE_OVERWRITTEN:
875 if (logfile)
876 fprintf(logfile, "200 File Overwrite: %s\n", fmt);
877 add_to_filelist_label:
878 if ((cp = strrchr(fmt, '.')) && (0 == strcmp (cp, ".py")))
879 add_to_filelist(fmt);
880 break;
882 /* Error Messages */
883 case ZLIB_ERROR:
884 MessageBox(GetFocus(), Buffer, "Error",
885 MB_OK | MB_ICONWARNING);
886 break;
888 case SYSTEM_ERROR:
889 SystemError(GetLastError(), Buffer);
890 break;
892 case NUM_FILES:
893 a = va_arg(marker, int);
894 b = va_arg(marker, int);
895 SendMessage(hDialog, WM_NUMFILES, 0, MAKELPARAM(0, a));
896 SendMessage(hDialog, WM_NEXTFILE, b,(LPARAM)fmt);
898 va_end(marker);
900 return result;
903 static char *MapExistingFile(char *pathname, DWORD *psize)
905 HANDLE hFile, hFileMapping;
906 DWORD nSizeLow, nSizeHigh;
907 char *data;
909 hFile = CreateFile(pathname,
910 GENERIC_READ, FILE_SHARE_READ, NULL,
911 OPEN_EXISTING,
912 FILE_ATTRIBUTE_NORMAL, NULL);
913 if (hFile == INVALID_HANDLE_VALUE)
914 return NULL;
915 nSizeLow = GetFileSize(hFile, &nSizeHigh);
916 hFileMapping = CreateFileMapping(hFile,
917 NULL, PAGE_READONLY, 0, 0, NULL);
918 CloseHandle(hFile);
920 if (hFileMapping == INVALID_HANDLE_VALUE)
921 return NULL;
923 data = MapViewOfFile(hFileMapping,
924 FILE_MAP_READ, 0, 0, 0);
926 CloseHandle(hFileMapping);
927 *psize = nSizeLow;
928 return data;
932 static void create_bitmap(HWND hwnd)
934 BITMAPFILEHEADER *bfh;
935 BITMAPINFO *bi;
936 HDC hdc;
938 if (!bitmap_bytes)
939 return;
941 if (hBitmap)
942 return;
944 hdc = GetDC(hwnd);
946 bfh = (BITMAPFILEHEADER *)bitmap_bytes;
947 bi = (BITMAPINFO *)(bitmap_bytes + sizeof(BITMAPFILEHEADER));
949 hBitmap = CreateDIBitmap(hdc,
950 &bi->bmiHeader,
951 CBM_INIT,
952 bitmap_bytes + bfh->bfOffBits,
954 DIB_RGB_COLORS);
955 ReleaseDC(hwnd, hdc);
958 /* Extract everything we need to begin the installation. Currently this
959 is the INI filename with install data, and the raw pre-install script
961 static BOOL ExtractInstallData(char *data, DWORD size, int *pexe_size,
962 char **out_ini_file, char **out_preinstall_script)
964 /* read the end of central directory record */
965 struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
966 (struct eof_cdir)];
968 int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
969 pe->ofsCDir;
971 int ofs = arc_start - sizeof (struct meta_data_hdr);
973 /* read meta_data info */
974 struct meta_data_hdr *pmd = (struct meta_data_hdr *)&data[ofs];
975 char *src, *dst;
976 char *ini_file;
977 char tempdir[MAX_PATH];
979 /* ensure that if we fail, we don't have garbage out pointers */
980 *out_ini_file = *out_preinstall_script = NULL;
982 if (pe->tag != 0x06054b50) {
983 return FALSE;
986 if (pmd->tag != 0x1234567B) {
987 return SystemError(0,
988 "Invalid cfgdata magic number (see bdist_wininst.py)");
990 if (ofs < 0) {
991 return FALSE;
994 if (pmd->bitmap_size) {
995 /* Store pointer to bitmap bytes */
996 bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
999 *pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
1001 src = ((char *)pmd) - pmd->uncomp_size;
1002 ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
1003 if (!ini_file)
1004 return FALSE;
1005 if (!GetTempPath(sizeof(tempdir), tempdir)
1006 || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
1007 SystemError(GetLastError(),
1008 "Could not create temporary file");
1009 return FALSE;
1012 dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
1013 0, 0, NULL/*notify*/);
1014 if (!dst)
1015 return FALSE;
1016 /* Up to the first \0 is the INI file data. */
1017 strncpy(dst, src, pmd->uncomp_size);
1018 src += strlen(dst) + 1;
1019 /* Up to next \0 is the pre-install script */
1020 *out_preinstall_script = strdup(src);
1021 *out_ini_file = ini_file;
1022 UnmapViewOfFile(dst);
1023 return TRUE;
1026 static void PumpMessages(void)
1028 MSG msg;
1029 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1030 TranslateMessage(&msg);
1031 DispatchMessage(&msg);
1035 LRESULT CALLBACK
1036 WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1038 HDC hdc;
1039 HFONT hFont;
1040 int h;
1041 PAINTSTRUCT ps;
1042 switch (msg) {
1043 case WM_PAINT:
1044 hdc = BeginPaint(hwnd, &ps);
1045 h = GetSystemMetrics(SM_CYSCREEN) / 10;
1046 hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
1047 0, 0, 0, 0, 0, 0, 0, "Times Roman");
1048 hFont = SelectObject(hdc, hFont);
1049 SetBkMode(hdc, TRANSPARENT);
1050 TextOut(hdc, 15, 15, title, strlen(title));
1051 SetTextColor(hdc, RGB(255, 255, 255));
1052 TextOut(hdc, 10, 10, title, strlen(title));
1053 DeleteObject(SelectObject(hdc, hFont));
1054 EndPaint(hwnd, &ps);
1055 return 0;
1057 return DefWindowProc(hwnd, msg, wParam, lParam);
1060 static HWND CreateBackground(char *title)
1062 WNDCLASS wc;
1063 HWND hwnd;
1064 char buffer[4096];
1066 wc.style = CS_VREDRAW | CS_HREDRAW;
1067 wc.lpfnWndProc = WindowProc;
1068 wc.cbWndExtra = 0;
1069 wc.cbClsExtra = 0;
1070 wc.hInstance = GetModuleHandle(NULL);
1071 wc.hIcon = NULL;
1072 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1073 wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
1074 wc.lpszMenuName = NULL;
1075 wc.lpszClassName = "SetupWindowClass";
1077 if (!RegisterClass(&wc))
1078 MessageBox(hwndMain,
1079 "Could not register window class",
1080 "Setup.exe", MB_OK);
1082 wsprintf(buffer, "Setup %s", title);
1083 hwnd = CreateWindow("SetupWindowClass",
1084 buffer,
1086 0, 0,
1087 GetSystemMetrics(SM_CXFULLSCREEN),
1088 GetSystemMetrics(SM_CYFULLSCREEN),
1089 NULL,
1090 NULL,
1091 GetModuleHandle(NULL),
1092 NULL);
1093 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
1094 UpdateWindow(hwnd);
1095 return hwnd;
1099 * Center a window on the screen
1101 static void CenterWindow(HWND hwnd)
1103 RECT rc;
1104 int w, h;
1106 GetWindowRect(hwnd, &rc);
1107 w = GetSystemMetrics(SM_CXSCREEN);
1108 h = GetSystemMetrics(SM_CYSCREEN);
1109 MoveWindow(hwnd,
1110 (w - (rc.right-rc.left))/2,
1111 (h - (rc.bottom-rc.top))/2,
1112 rc.right-rc.left, rc.bottom-rc.top, FALSE);
1115 #include <prsht.h>
1117 BOOL CALLBACK
1118 IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1120 LPNMHDR lpnm;
1121 char Buffer[4096];
1123 switch (msg) {
1124 case WM_INITDIALOG:
1125 create_bitmap(hwnd);
1126 if(hBitmap)
1127 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1128 IMAGE_BITMAP, (LPARAM)hBitmap);
1129 CenterWindow(GetParent(hwnd));
1130 wsprintf(Buffer,
1131 "This Wizard will install %s on your computer. "
1132 "Click Next to continue "
1133 "or Cancel to exit the Setup Wizard.",
1134 meta_name);
1135 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1136 SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
1137 SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
1138 return FALSE;
1140 case WM_NOTIFY:
1141 lpnm = (LPNMHDR) lParam;
1143 switch (lpnm->code) {
1144 case PSN_SETACTIVE:
1145 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
1146 break;
1148 case PSN_WIZNEXT:
1149 break;
1151 case PSN_RESET:
1152 break;
1154 default:
1155 break;
1158 return FALSE;
1161 #ifdef USE_OTHER_PYTHON_VERSIONS
1162 /* These are really private variables used to communicate
1163 * between StatusRoutine and CheckPythonExe
1165 char bound_image_dll[_MAX_PATH];
1166 int bound_image_major;
1167 int bound_image_minor;
1169 static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
1170 PSTR ImageName,
1171 PSTR DllName,
1172 ULONG Va,
1173 ULONG Parameter)
1175 char fname[_MAX_PATH];
1176 int int_version;
1178 switch(reason) {
1179 case BindOutOfMemory:
1180 case BindRvaToVaFailed:
1181 case BindNoRoomInImage:
1182 case BindImportProcedureFailed:
1183 break;
1185 case BindImportProcedure:
1186 case BindForwarder:
1187 case BindForwarderNOT:
1188 case BindImageModified:
1189 case BindExpandFileHeaders:
1190 case BindImageComplete:
1191 case BindSymbolsNotUpdated:
1192 case BindMismatchedSymbols:
1193 case BindImportModuleFailed:
1194 break;
1196 case BindImportModule:
1197 if (1 == sscanf(DllName, "python%d", &int_version)) {
1198 SearchPath(NULL, DllName, NULL, sizeof(fname),
1199 fname, NULL);
1200 strcpy(bound_image_dll, fname);
1201 bound_image_major = int_version / 10;
1202 bound_image_minor = int_version % 10;
1203 OutputDebugString("BOUND ");
1204 OutputDebugString(fname);
1205 OutputDebugString("\n");
1207 break;
1209 return TRUE;
1214 static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1216 void (__cdecl * Py_Initialize)(void);
1217 void (__cdecl * Py_SetProgramName)(char *);
1218 void (__cdecl * Py_Finalize)(void);
1219 void* (__cdecl * PySys_GetObject)(char *);
1220 void (__cdecl * PySys_SetArgv)(int, char **);
1221 char* (__cdecl * Py_GetPrefix)(void);
1222 char* (__cdecl * Py_GetPath)(void);
1223 HINSTANCE hPython;
1224 LPSTR prefix = NULL;
1225 int (__cdecl * PyRun_SimpleString)(char *);
1228 char Buffer[256];
1229 wsprintf(Buffer, "PYTHONHOME=%s", exe);
1230 *strrchr(Buffer, '\\') = '\0';
1231 // MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1232 _putenv(Buffer);
1233 _putenv("PYTHONPATH=");
1236 hPython = LoadLibrary(dll);
1237 if (!hPython)
1238 return NULL;
1239 Py_Initialize = (void (*)(void))GetProcAddress
1240 (hPython,"Py_Initialize");
1242 PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1243 (hPython,"PySys_SetArgv");
1245 PyRun_SimpleString = (int (*)(char *))GetProcAddress
1246 (hPython,"PyRun_SimpleString");
1248 Py_SetProgramName = (void (*)(char *))GetProcAddress
1249 (hPython,"Py_SetProgramName");
1251 PySys_GetObject = (void* (*)(char *))GetProcAddress
1252 (hPython,"PySys_GetObject");
1254 Py_GetPrefix = (char * (*)(void))GetProcAddress
1255 (hPython,"Py_GetPrefix");
1257 Py_GetPath = (char * (*)(void))GetProcAddress
1258 (hPython,"Py_GetPath");
1260 Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1261 "Py_Finalize");
1262 Py_SetProgramName(exe);
1263 Py_Initialize();
1264 PySys_SetArgv(1, &exe);
1266 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1267 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
1269 Py_Finalize();
1270 FreeLibrary(hPython);
1272 return prefix;
1275 static BOOL
1276 CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1278 bound_image_dll[0] = '\0';
1279 if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1280 pathname,
1281 NULL,
1282 NULL,
1283 StatusRoutine))
1284 return SystemError(0, "Could not bind image");
1285 if (bound_image_dll[0] == '\0')
1286 return SystemError(0, "Does not seem to be a python executable");
1287 *pmajor = bound_image_major;
1288 *pminor = bound_image_minor;
1289 if (version && *version) {
1290 char core_version[12];
1291 wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1292 if (strcmp(version, core_version))
1293 return SystemError(0, "Wrong Python version");
1295 get_sys_prefix(pathname, bound_image_dll);
1296 return TRUE;
1300 * Browse for other python versions. Insert it into the listbox specified
1301 * by hwnd. version, if not NULL or empty, is the version required.
1303 static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1305 char vers_name[_MAX_PATH + 80];
1306 DWORD itemindex;
1307 OPENFILENAME of;
1308 char pathname[_MAX_PATH];
1309 DWORD result;
1311 strcpy(pathname, "python.exe");
1313 memset(&of, 0, sizeof(of));
1314 of.lStructSize = sizeof(OPENFILENAME);
1315 of.hwndOwner = GetParent(hwnd);
1316 of.hInstance = NULL;
1317 of.lpstrFilter = "python.exe\0python.exe\0";
1318 of.lpstrCustomFilter = NULL;
1319 of.nMaxCustFilter = 0;
1320 of.nFilterIndex = 1;
1321 of.lpstrFile = pathname;
1322 of.nMaxFile = sizeof(pathname);
1323 of.lpstrFileTitle = NULL;
1324 of.nMaxFileTitle = 0;
1325 of.lpstrInitialDir = NULL;
1326 of.lpstrTitle = "Python executable";
1327 of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1328 of.lpstrDefExt = "exe";
1330 result = GetOpenFileName(&of);
1331 if (result) {
1332 int major, minor;
1333 if (!CheckPythonExe(pathname, version, &major, &minor)) {
1334 return FALSE;
1336 *strrchr(pathname, '\\') = '\0';
1337 wsprintf(vers_name, "Python Version %d.%d in %s",
1338 major, minor, pathname);
1339 itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1340 (LPARAM)(LPSTR)vers_name);
1341 SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1342 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1343 (LPARAM)(LPSTR)strdup(pathname));
1344 return TRUE;
1346 return FALSE;
1348 #endif /* USE_OTHER_PYTHON_VERSIONS */
1350 typedef struct _InstalledVersionInfo {
1351 char prefix[MAX_PATH+1]; // sys.prefix directory.
1352 HKEY hkey; // Is this Python in HKCU or HKLM?
1353 } InstalledVersionInfo;
1357 * Fill the listbox specified by hwnd with all python versions found
1358 * in the registry. version, if not NULL or empty, is the version
1359 * required.
1361 static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1363 DWORD index = 0;
1364 char core_version[80];
1365 HKEY hKey;
1366 BOOL result = TRUE;
1367 DWORD bufsize;
1369 if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1370 "Software\\Python\\PythonCore",
1371 0, KEY_READ, &hKey))
1372 return FALSE;
1373 bufsize = sizeof(core_version);
1374 while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1375 core_version, &bufsize, NULL,
1376 NULL, NULL, NULL)) {
1377 char subkey_name[80], vers_name[80];
1378 int itemindex;
1379 DWORD value_size;
1380 HKEY hk;
1382 bufsize = sizeof(core_version);
1383 ++index;
1384 if (version && *version && strcmp(version, core_version))
1385 continue;
1387 wsprintf(vers_name, "Python Version %s (found in registry)",
1388 core_version);
1389 wsprintf(subkey_name,
1390 "Software\\Python\\PythonCore\\%s\\InstallPath",
1391 core_version);
1392 if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
1393 InstalledVersionInfo *ivi =
1394 (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
1395 value_size = sizeof(ivi->prefix);
1396 if (ivi &&
1397 ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
1398 ivi->prefix, &value_size)) {
1399 itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
1400 (LPARAM)(LPSTR)vers_name);
1401 ivi->hkey = hkRoot;
1402 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1403 (LPARAM)(LPSTR)ivi);
1405 RegCloseKey(hk);
1408 RegCloseKey(hKey);
1409 return result;
1412 /* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1413 BOOL HasLocalMachinePrivs()
1415 HKEY hKey;
1416 DWORD result;
1417 static char KeyName[] =
1418 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1420 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1421 KeyName,
1423 KEY_CREATE_SUB_KEY,
1424 &hKey);
1425 if (result==0)
1426 RegCloseKey(hKey);
1427 return result==0;
1430 // Check the root registry key to use - either HKLM or HKCU.
1431 // If Python is installed in HKCU, then our extension also must be installed
1432 // in HKCU - as Python won't be available for other users, we shouldn't either
1433 // (and will fail if we are!)
1434 // If Python is installed in HKLM, then we will also prefer to use HKLM, but
1435 // this may not be possible - so we silently fall back to HKCU.
1437 // We assume hkey_root is already set to where Python itself is installed.
1438 void CheckRootKey(HWND hwnd)
1440 if (hkey_root==HKEY_CURRENT_USER) {
1441 ; // as above, always install ourself in HKCU too.
1442 } else if (hkey_root==HKEY_LOCAL_MACHINE) {
1443 // Python in HKLM, but we may or may not have permissions there.
1444 // Open the uninstall key with 'create' permissions - if this fails,
1445 // we don't have permission.
1446 if (!HasLocalMachinePrivs())
1447 hkey_root = HKEY_CURRENT_USER;
1448 } else {
1449 MessageBox(hwnd, "Don't know Python's installation type",
1450 "Strange", MB_OK | MB_ICONSTOP);
1451 /* Default to wherever they can, but preferring HKLM */
1452 hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1456 /* Return the installation scheme depending on Python version number */
1457 SCHEME *GetScheme(int major, int minor)
1459 if (major > 2)
1460 return new_scheme;
1461 else if((major == 2) && (minor >= 2))
1462 return new_scheme;
1463 return old_scheme;
1466 BOOL CALLBACK
1467 SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1469 LPNMHDR lpnm;
1471 switch (msg) {
1472 case WM_INITDIALOG:
1473 if (hBitmap)
1474 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1475 IMAGE_BITMAP, (LPARAM)hBitmap);
1476 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1477 HKEY_LOCAL_MACHINE, target_version);
1478 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1479 HKEY_CURRENT_USER, target_version);
1480 { /* select the last entry which is the highest python
1481 version found */
1482 int count;
1483 count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1484 LB_GETCOUNT, 0, 0);
1485 if (count && count != LB_ERR)
1486 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1487 count-1, 0);
1489 /* If a specific Python version is required,
1490 * display a prominent notice showing this fact.
1492 if (target_version && target_version[0]) {
1493 char buffer[4096];
1494 wsprintf(buffer,
1495 "Python %s is required for this package. "
1496 "Select installation to use:",
1497 target_version);
1498 SetDlgItemText(hwnd, IDC_TITLE, buffer);
1501 if (count == 0) {
1502 char Buffer[4096];
1503 char *msg;
1504 if (target_version && target_version[0]) {
1505 wsprintf(Buffer,
1506 "Python version %s required, which was not found"
1507 " in the registry.", target_version);
1508 msg = Buffer;
1509 } else
1510 msg = "No Python installation found in the registry.";
1511 MessageBox(hwnd, msg, "Cannot install",
1512 MB_OK | MB_ICONSTOP);
1515 goto UpdateInstallDir;
1516 break;
1518 case WM_COMMAND:
1519 switch (LOWORD(wParam)) {
1521 case IDC_OTHERPYTHON:
1522 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1523 target_version))
1524 goto UpdateInstallDir;
1525 break;
1527 case IDC_VERSIONS_LIST:
1528 switch (HIWORD(wParam)) {
1529 int id;
1530 case LBN_SELCHANGE:
1531 UpdateInstallDir:
1532 PropSheet_SetWizButtons(GetParent(hwnd),
1533 PSWIZB_BACK | PSWIZB_NEXT);
1534 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1535 LB_GETCURSEL, 0, 0);
1536 if (id == LB_ERR) {
1537 PropSheet_SetWizButtons(GetParent(hwnd),
1538 PSWIZB_BACK);
1539 SetDlgItemText(hwnd, IDC_PATH, "");
1540 SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1541 strcpy(python_dir, "");
1542 strcpy(pythondll, "");
1543 } else {
1544 char *pbuf;
1545 int result;
1546 InstalledVersionInfo *ivi;
1547 PropSheet_SetWizButtons(GetParent(hwnd),
1548 PSWIZB_BACK | PSWIZB_NEXT);
1549 /* Get the python directory */
1550 ivi = (InstalledVersionInfo *)
1551 SendDlgItemMessage(hwnd,
1552 IDC_VERSIONS_LIST,
1553 LB_GETITEMDATA,
1556 hkey_root = ivi->hkey;
1557 strcpy(python_dir, ivi->prefix);
1558 SetDlgItemText(hwnd, IDC_PATH, python_dir);
1559 /* retrieve the python version and pythondll to use */
1560 result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1561 LB_GETTEXTLEN, (WPARAM)id, 0);
1562 pbuf = (char *)malloc(result + 1);
1563 if (pbuf) {
1564 /* guess the name of the python-dll */
1565 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1566 LB_GETTEXT, (WPARAM)id,
1567 (LPARAM)pbuf);
1568 result = sscanf(pbuf, "Python Version %d.%d",
1569 &py_major, &py_minor);
1570 if (result == 2) {
1571 #ifdef _DEBUG
1572 wsprintf(pythondll, "python%d%d_d.dll",
1573 py_major, py_minor);
1574 #else
1575 wsprintf(pythondll, "python%d%d.dll",
1576 py_major, py_minor);
1577 #endif
1579 free(pbuf);
1580 } else
1581 strcpy(pythondll, "");
1582 /* retrieve the scheme for this version */
1584 char install_path[_MAX_PATH];
1585 SCHEME *scheme = GetScheme(py_major, py_minor);
1586 strcpy(install_path, python_dir);
1587 if (install_path[strlen(install_path)-1] != '\\')
1588 strcat(install_path, "\\");
1589 strcat(install_path, scheme[0].prefix);
1590 SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1594 break;
1596 return 0;
1598 case WM_NOTIFY:
1599 lpnm = (LPNMHDR) lParam;
1601 switch (lpnm->code) {
1602 int id;
1603 case PSN_SETACTIVE:
1604 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1605 LB_GETCURSEL, 0, 0);
1606 if (id == LB_ERR)
1607 PropSheet_SetWizButtons(GetParent(hwnd),
1608 PSWIZB_BACK);
1609 else
1610 PropSheet_SetWizButtons(GetParent(hwnd),
1611 PSWIZB_BACK | PSWIZB_NEXT);
1612 break;
1614 case PSN_WIZNEXT:
1615 break;
1617 case PSN_WIZFINISH:
1618 break;
1620 case PSN_RESET:
1621 break;
1623 default:
1624 break;
1627 return 0;
1630 static BOOL OpenLogfile(char *dir)
1632 char buffer[_MAX_PATH+1];
1633 time_t ltime;
1634 struct tm *now;
1635 long result;
1636 HKEY hKey, hSubkey;
1637 char subkey_name[256];
1638 static char KeyName[] =
1639 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1640 const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
1641 "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
1642 DWORD disposition;
1644 /* Use Create, as the Uninstall subkey may not exist under HKCU.
1645 Use CreateKeyEx, so we can specify a SAM specifying write access
1647 result = RegCreateKeyEx(hkey_root,
1648 KeyName,
1649 0, /* reserved */
1650 NULL, /* class */
1651 0, /* options */
1652 KEY_CREATE_SUB_KEY, /* sam */
1653 NULL, /* security */
1654 &hKey, /* result key */
1655 NULL); /* disposition */
1656 if (result != ERROR_SUCCESS) {
1657 if (result == ERROR_ACCESS_DENIED) {
1658 /* This should no longer be able to happen - we have already
1659 checked if they have permissions in HKLM, and all users
1660 should have write access to HKCU.
1662 MessageBox(GetFocus(),
1663 "You do not seem to have sufficient access rights\n"
1664 "on this machine to install this software",
1665 NULL,
1666 MB_OK | MB_ICONSTOP);
1667 return FALSE;
1668 } else {
1669 MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1673 sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1674 logfile = fopen(buffer, "a");
1675 time(&ltime);
1676 now = localtime(&ltime);
1677 strftime(buffer, sizeof(buffer),
1678 "*** Installation started %Y/%m/%d %H:%M ***\n",
1679 localtime(&ltime));
1680 fprintf(logfile, buffer);
1681 fprintf(logfile, "Source: %s\n", modulename);
1683 /* Root key must be first entry processed by uninstaller. */
1684 fprintf(logfile, "999 Root Key: %s\n", root_name);
1686 sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
1688 result = RegCreateKeyEx(hKey, subkey_name,
1689 0, NULL, 0,
1690 KEY_WRITE,
1691 NULL,
1692 &hSubkey,
1693 &disposition);
1695 if (result != ERROR_SUCCESS)
1696 MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
1698 RegCloseKey(hKey);
1700 if (disposition == REG_CREATED_NEW_KEY)
1701 fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
1703 sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
1705 result = RegSetValueEx(hSubkey, "DisplayName",
1707 REG_SZ,
1708 buffer,
1709 strlen(buffer)+1);
1711 if (result != ERROR_SUCCESS)
1712 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1714 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1715 KeyName, subkey_name, "DisplayName", buffer);
1718 FILE *fp;
1719 sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1720 fp = fopen(buffer, "wb");
1721 fwrite(arc_data, exe_size, 1, fp);
1722 fclose(fp);
1724 sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1725 dir, meta_name, dir, meta_name);
1727 result = RegSetValueEx(hSubkey, "UninstallString",
1729 REG_SZ,
1730 buffer,
1731 strlen(buffer)+1);
1733 if (result != ERROR_SUCCESS)
1734 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1736 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1737 KeyName, subkey_name, "UninstallString", buffer);
1739 return TRUE;
1742 static void CloseLogfile(void)
1744 char buffer[_MAX_PATH+1];
1745 time_t ltime;
1746 struct tm *now;
1748 time(&ltime);
1749 now = localtime(&ltime);
1750 strftime(buffer, sizeof(buffer),
1751 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1752 localtime(&ltime));
1753 fprintf(logfile, buffer);
1754 if (logfile)
1755 fclose(logfile);
1758 BOOL CALLBACK
1759 InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1761 LPNMHDR lpnm;
1762 char Buffer[4096];
1763 SCHEME *scheme;
1765 switch (msg) {
1766 case WM_INITDIALOG:
1767 if (hBitmap)
1768 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1769 IMAGE_BITMAP, (LPARAM)hBitmap);
1770 wsprintf(Buffer,
1771 "Click Next to begin the installation of %s. "
1772 "If you want to review or change any of your "
1773 " installation settings, click Back. "
1774 "Click Cancel to exit the wizard.",
1775 meta_name);
1776 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1777 SetDlgItemText(hwnd, IDC_INFO, "Ready to install");
1778 break;
1780 case WM_NUMFILES:
1781 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1782 PumpMessages();
1783 return TRUE;
1785 case WM_NEXTFILE:
1786 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1788 SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1789 PumpMessages();
1790 return TRUE;
1792 case WM_NOTIFY:
1793 lpnm = (LPNMHDR) lParam;
1795 switch (lpnm->code) {
1796 case PSN_SETACTIVE:
1797 PropSheet_SetWizButtons(GetParent(hwnd),
1798 PSWIZB_BACK | PSWIZB_NEXT);
1799 break;
1801 case PSN_WIZFINISH:
1802 break;
1804 case PSN_WIZNEXT:
1805 /* Handle a Next button click here */
1806 hDialog = hwnd;
1807 success = TRUE;
1809 /* Disable the buttons while we work. Sending CANCELTOCLOSE has
1810 the effect of disabling the cancel button, which is a) as we
1811 do everything synchronously we can't cancel, and b) the next
1812 step is 'finished', when it is too late to cancel anyway.
1813 The next step being 'Finished' means we also don't need to
1814 restore the button state back */
1815 PropSheet_SetWizButtons(GetParent(hwnd), 0);
1816 SendMessage(GetParent(hwnd), PSM_CANCELTOCLOSE, 0, 0);
1817 /* Make sure the installation directory name ends in a */
1818 /* backslash */
1819 if (python_dir[strlen(python_dir)-1] != '\\')
1820 strcat(python_dir, "\\");
1821 /* Strip the trailing backslash again */
1822 python_dir[strlen(python_dir)-1] = '\0';
1824 CheckRootKey(hwnd);
1826 if (!OpenLogfile(python_dir))
1827 break;
1830 * The scheme we have to use depends on the Python version...
1831 if sys.version < "2.2":
1832 WINDOWS_SCHEME = {
1833 'purelib': '$base',
1834 'platlib': '$base',
1835 'headers': '$base/Include/$dist_name',
1836 'scripts': '$base/Scripts',
1837 'data' : '$base',
1839 else:
1840 WINDOWS_SCHEME = {
1841 'purelib': '$base/Lib/site-packages',
1842 'platlib': '$base/Lib/site-packages',
1843 'headers': '$base/Include/$dist_name',
1844 'scripts': '$base/Scripts',
1845 'data' : '$base',
1848 scheme = GetScheme(py_major, py_minor);
1849 /* Run the pre-install script. */
1850 if (pre_install_script && *pre_install_script) {
1851 SetDlgItemText (hwnd, IDC_TITLE,
1852 "Running pre-installation script");
1853 run_simple_script(pre_install_script);
1855 if (!success) {
1856 break;
1858 /* Extract all files from the archive */
1859 SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
1860 if (!unzip_archive (scheme,
1861 python_dir, arc_data,
1862 arc_size, notify))
1863 set_failure_reason("Failed to unzip installation files");
1864 /* Compile the py-files */
1865 if (success && pyc_compile) {
1866 int errors;
1867 HINSTANCE hPython;
1868 SetDlgItemText(hwnd, IDC_TITLE,
1869 "Compiling files to .pyc...");
1871 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
1872 hPython = LoadPythonDll(pythondll);
1873 if (hPython) {
1874 errors = compile_filelist(hPython, FALSE);
1875 FreeLibrary(hPython);
1877 /* Compilation errors are intentionally ignored:
1878 * Python2.0 contains a bug which will result
1879 * in sys.path containing garbage under certain
1880 * circumstances, and an error message will only
1881 * confuse the user.
1884 if (success && pyo_compile) {
1885 int errors;
1886 HINSTANCE hPython;
1887 SetDlgItemText(hwnd, IDC_TITLE,
1888 "Compiling files to .pyo...");
1890 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
1891 hPython = LoadPythonDll(pythondll);
1892 if (hPython) {
1893 errors = compile_filelist(hPython, TRUE);
1894 FreeLibrary(hPython);
1896 /* Errors ignored: see above */
1900 break;
1902 case PSN_RESET:
1903 break;
1905 default:
1906 break;
1909 return 0;
1913 BOOL CALLBACK
1914 FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1916 LPNMHDR lpnm;
1918 switch (msg) {
1919 case WM_INITDIALOG:
1920 if (hBitmap)
1921 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1922 IMAGE_BITMAP, (LPARAM)hBitmap);
1923 if (!success)
1924 SetDlgItemText(hwnd, IDC_INFO, get_failure_reason());
1926 /* async delay: will show the dialog box completely before
1927 the install_script is started */
1928 PostMessage(hwnd, WM_USER, 0, 0L);
1929 return TRUE;
1931 case WM_USER:
1933 if (success && install_script && install_script[0]) {
1934 char fname[MAX_PATH];
1935 char *tempname;
1936 FILE *fp;
1937 char buffer[4096];
1938 int n;
1939 HCURSOR hCursor;
1940 HINSTANCE hPython;
1942 char *argv[3] = {NULL, "-install", NULL};
1944 SetDlgItemText(hwnd, IDC_TITLE,
1945 "Please wait while running postinstall script...");
1946 strcpy(fname, python_dir);
1947 strcat(fname, "\\Scripts\\");
1948 strcat(fname, install_script);
1950 if (logfile)
1951 fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
1953 tempname = tempnam(NULL, NULL);
1955 if (!freopen(tempname, "a", stderr))
1956 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
1957 if (!freopen(tempname, "a", stdout))
1958 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
1960 if (0 != setvbuf(stdout, NULL, _IONBF, 0))
1961 MessageBox(GetFocus(), "setvbuf stdout", NULL, MB_OK);
1963 hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
1965 argv[0] = fname;
1967 hPython = LoadPythonDll(pythondll);
1968 if (hPython) {
1969 int result;
1970 result = run_installscript(hPython, fname, 2, argv);
1971 if (-1 == result) {
1972 fprintf(stderr, "*** run_installscript: internal error 0x%X ***\n", result);
1974 FreeLibrary(hPython);
1975 } else {
1976 fprintf(stderr, "*** Could not load Python ***");
1978 fflush(stderr);
1979 fclose(stderr);
1980 fflush(stdout);
1981 fclose(stdout);
1983 fp = fopen(tempname, "rb");
1984 n = fread(buffer, 1, sizeof(buffer), fp);
1985 fclose(fp);
1986 remove(tempname);
1988 buffer[n] = '\0';
1990 SetDlgItemText(hwnd, IDC_INFO, buffer);
1991 SetDlgItemText(hwnd, IDC_TITLE,
1992 "Postinstall script finished.\n"
1993 "Click the Finish button to exit the Setup wizard.");
1995 SetCursor(hCursor);
1996 CloseLogfile();
1999 return TRUE;
2001 case WM_NOTIFY:
2002 lpnm = (LPNMHDR) lParam;
2004 switch (lpnm->code) {
2005 case PSN_SETACTIVE: /* Enable the Finish button */
2006 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH);
2007 break;
2009 case PSN_WIZNEXT:
2010 break;
2012 case PSN_WIZFINISH:
2013 break;
2015 case PSN_RESET:
2016 break;
2018 default:
2019 break;
2022 return 0;
2025 void RunWizard(HWND hwnd)
2027 PROPSHEETPAGE psp = {0};
2028 HPROPSHEETPAGE ahpsp[4] = {0};
2029 PROPSHEETHEADER psh = {0};
2031 /* Display module information */
2032 psp.dwSize = sizeof(psp);
2033 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2034 psp.hInstance = GetModuleHandle (NULL);
2035 psp.lParam = 0;
2036 psp.pfnDlgProc = IntroDlgProc;
2037 psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO);
2039 ahpsp[0] = CreatePropertySheetPage(&psp);
2041 /* Select python version to use */
2042 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2043 psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTPYTHON);
2044 psp.pfnDlgProc = SelectPythonDlgProc;
2046 ahpsp[1] = CreatePropertySheetPage(&psp);
2048 /* Install the files */
2049 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2050 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFILES);
2051 psp.pfnDlgProc = InstallFilesDlgProc;
2053 ahpsp[2] = CreatePropertySheetPage(&psp);
2055 /* Show success or failure */
2056 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2057 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHED);
2058 psp.pfnDlgProc = FinishedDlgProc;
2060 ahpsp[3] = CreatePropertySheetPage(&psp);
2062 /* Create the property sheet */
2063 psh.dwSize = sizeof(psh);
2064 psh.hInstance = GetModuleHandle(NULL);
2065 psh.hwndParent = hwnd;
2066 psh.phpage = ahpsp;
2067 psh.dwFlags = PSH_WIZARD/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
2068 psh.pszbmWatermark = NULL;
2069 psh.pszbmHeader = NULL;
2070 psh.nStartPage = 0;
2071 psh.nPages = 4;
2073 PropertySheet(&psh);
2076 int DoInstall(void)
2078 char ini_buffer[4096];
2080 /* Read installation information */
2081 GetPrivateProfileString("Setup", "title", "", ini_buffer,
2082 sizeof(ini_buffer), ini_file);
2083 unescape(title, ini_buffer, sizeof(title));
2085 GetPrivateProfileString("Setup", "info", "", ini_buffer,
2086 sizeof(ini_buffer), ini_file);
2087 unescape(info, ini_buffer, sizeof(info));
2089 GetPrivateProfileString("Setup", "build_info", "", build_info,
2090 sizeof(build_info), ini_file);
2092 pyc_compile = GetPrivateProfileInt("Setup", "target_compile", 1,
2093 ini_file);
2094 pyo_compile = GetPrivateProfileInt("Setup", "target_optimize", 1,
2095 ini_file);
2097 GetPrivateProfileString("Setup", "target_version", "",
2098 target_version, sizeof(target_version),
2099 ini_file);
2101 GetPrivateProfileString("metadata", "name", "",
2102 meta_name, sizeof(meta_name),
2103 ini_file);
2105 GetPrivateProfileString("Setup", "install_script", "",
2106 install_script, sizeof(install_script),
2107 ini_file);
2110 hwndMain = CreateBackground(title);
2112 RunWizard(hwndMain);
2114 /* Clean up */
2115 UnmapViewOfFile(arc_data);
2116 if (ini_file)
2117 DeleteFile(ini_file);
2119 if (hBitmap)
2120 DeleteObject(hBitmap);
2122 return 0;
2125 /*********************** uninstall section ******************************/
2127 static int compare(const void *p1, const void *p2)
2129 return strcmp(*(char **)p2, *(char **)p1);
2133 * Commit suicide (remove the uninstaller itself).
2135 * Create a batch file to first remove the uninstaller
2136 * (will succeed after it has finished), then the batch file itself.
2138 * This technique has been demonstrated by Jeff Richter,
2139 * MSJ 1/1996
2141 void remove_exe(void)
2143 char exename[_MAX_PATH];
2144 char batname[_MAX_PATH];
2145 FILE *fp;
2146 STARTUPINFO si;
2147 PROCESS_INFORMATION pi;
2149 GetModuleFileName(NULL, exename, sizeof(exename));
2150 sprintf(batname, "%s.bat", exename);
2151 fp = fopen(batname, "w");
2152 fprintf(fp, ":Repeat\n");
2153 fprintf(fp, "del \"%s\"\n", exename);
2154 fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
2155 fprintf(fp, "del \"%s\"\n", batname);
2156 fclose(fp);
2158 ZeroMemory(&si, sizeof(si));
2159 si.cb = sizeof(si);
2160 si.dwFlags = STARTF_USESHOWWINDOW;
2161 si.wShowWindow = SW_HIDE;
2162 if (CreateProcess(NULL,
2163 batname,
2164 NULL,
2165 NULL,
2166 FALSE,
2167 CREATE_SUSPENDED | IDLE_PRIORITY_CLASS,
2168 NULL,
2169 "\\",
2170 &si,
2171 &pi)) {
2172 SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE);
2173 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
2174 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
2175 CloseHandle(pi.hProcess);
2176 ResumeThread(pi.hThread);
2177 CloseHandle(pi.hThread);
2181 void DeleteRegistryKey(char *string)
2183 char *keyname;
2184 char *subkeyname;
2185 char *delim;
2186 HKEY hKey;
2187 long result;
2188 char *line;
2190 line = strdup(string); /* so we can change it */
2192 keyname = strchr(line, '[');
2193 if (!keyname)
2194 return;
2195 ++keyname;
2197 subkeyname = strchr(keyname, ']');
2198 if (!subkeyname)
2199 return;
2200 *subkeyname++='\0';
2201 delim = strchr(subkeyname, '\n');
2202 if (delim)
2203 *delim = '\0';
2205 result = RegOpenKeyEx(hkey_root,
2206 keyname,
2208 KEY_WRITE,
2209 &hKey);
2211 if (result != ERROR_SUCCESS)
2212 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2213 else {
2214 result = RegDeleteKey(hKey, subkeyname);
2215 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
2216 MessageBox(GetFocus(), string, "Could not delete key", MB_OK);
2217 RegCloseKey(hKey);
2219 free(line);
2222 void DeleteRegistryValue(char *string)
2224 char *keyname;
2225 char *valuename;
2226 char *value;
2227 HKEY hKey;
2228 long result;
2229 char *line;
2231 line = strdup(string); /* so we can change it */
2233 /* Format is 'Reg DB Value: [key]name=value' */
2234 keyname = strchr(line, '[');
2235 if (!keyname)
2236 return;
2237 ++keyname;
2238 valuename = strchr(keyname, ']');
2239 if (!valuename)
2240 return;
2241 *valuename++ = '\0';
2242 value = strchr(valuename, '=');
2243 if (!value)
2244 return;
2246 *value++ = '\0';
2248 result = RegOpenKeyEx(hkey_root,
2249 keyname,
2251 KEY_WRITE,
2252 &hKey);
2253 if (result != ERROR_SUCCESS)
2254 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2255 else {
2256 result = RegDeleteValue(hKey, valuename);
2257 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
2258 MessageBox(GetFocus(), string, "Could not delete value", MB_OK);
2259 RegCloseKey(hKey);
2261 free(line);
2264 BOOL MyDeleteFile(char *line)
2266 char *pathname = strchr(line, ':');
2267 if (!pathname)
2268 return FALSE;
2269 ++pathname;
2270 while (isspace(*pathname))
2271 ++pathname;
2272 return DeleteFile(pathname);
2275 BOOL MyRemoveDirectory(char *line)
2277 char *pathname = strchr(line, ':');
2278 if (!pathname)
2279 return FALSE;
2280 ++pathname;
2281 while (isspace(*pathname))
2282 ++pathname;
2283 return RemoveDirectory(pathname);
2286 BOOL Run_RemoveScript(char *line)
2288 char *dllname;
2289 char *scriptname;
2290 static char lastscript[MAX_PATH];
2292 /* Format is 'Run Scripts: [pythondll]scriptname' */
2293 /* XXX Currently, pythondll carries no path!!! */
2294 dllname = strchr(line, '[');
2295 if (!dllname)
2296 return FALSE;
2297 ++dllname;
2298 scriptname = strchr(dllname, ']');
2299 if (!scriptname)
2300 return FALSE;
2301 *scriptname++ = '\0';
2302 /* this function may be called more than one time with the same
2303 script, only run it one time */
2304 if (strcmp(lastscript, scriptname)) {
2305 HINSTANCE hPython;
2306 char *argv[3] = {NULL, "-remove", NULL};
2307 char buffer[4096];
2308 FILE *fp;
2309 char *tempname;
2310 int n;
2312 argv[0] = scriptname;
2314 tempname = tempnam(NULL, NULL);
2316 if (!freopen(tempname, "a", stderr))
2317 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
2318 if (!freopen(tempname, "a", stdout))
2319 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
2321 hPython = LoadLibrary(dllname);
2322 if (hPython) {
2323 if (0x80000000 == run_installscript(hPython, scriptname, 2, argv))
2324 fprintf(stderr, "*** Could not load Python ***");
2325 FreeLibrary(hPython);
2328 fflush(stderr);
2329 fclose(stderr);
2330 fflush(stdout);
2331 fclose(stdout);
2333 fp = fopen(tempname, "rb");
2334 n = fread(buffer, 1, sizeof(buffer), fp);
2335 fclose(fp);
2336 remove(tempname);
2338 buffer[n] = '\0';
2339 if (buffer[0])
2340 MessageBox(GetFocus(), buffer, "uninstall-script", MB_OK);
2342 strcpy(lastscript, scriptname);
2344 return TRUE;
2347 int DoUninstall(int argc, char **argv)
2349 FILE *logfile;
2350 char buffer[4096];
2351 int nLines = 0;
2352 int i;
2353 char *cp;
2354 int nFiles = 0;
2355 int nDirs = 0;
2356 int nErrors = 0;
2357 char **lines;
2358 int lines_buffer_size = 10;
2360 if (argc != 3) {
2361 MessageBox(NULL,
2362 "Wrong number of args",
2363 NULL,
2364 MB_OK);
2365 return 1; /* Error */
2367 if (strcmp(argv[1], "-u")) {
2368 MessageBox(NULL,
2369 "2. arg is not -u",
2370 NULL,
2371 MB_OK);
2372 return 1; /* Error */
2375 logfile = fopen(argv[2], "r");
2376 if (!logfile) {
2377 MessageBox(NULL,
2378 "could not open logfile",
2379 NULL,
2380 MB_OK);
2381 return 1; /* Error */
2384 lines = (char **)malloc(sizeof(char *) * lines_buffer_size);
2385 if (!lines)
2386 return SystemError(0, "Out of memory");
2388 /* Read the whole logfile, realloacting the buffer */
2389 while (fgets(buffer, sizeof(buffer), logfile)) {
2390 int len = strlen(buffer);
2391 /* remove trailing white space */
2392 while (isspace(buffer[len-1]))
2393 len -= 1;
2394 buffer[len] = '\0';
2395 lines[nLines++] = strdup(buffer);
2396 if (nLines >= lines_buffer_size) {
2397 lines_buffer_size += 10;
2398 lines = (char **)realloc(lines,
2399 sizeof(char *) * lines_buffer_size);
2400 if (!lines)
2401 return SystemError(0, "Out of memory");
2404 fclose(logfile);
2406 /* Sort all the lines, so that highest 3-digit codes are first */
2407 qsort(&lines[0], nLines, sizeof(char *),
2408 compare);
2410 if (IDYES != MessageBox(NULL,
2411 "Are you sure you want to remove\n"
2412 "this package from your computer?",
2413 "Please confirm",
2414 MB_YESNO | MB_ICONQUESTION))
2415 return 0;
2417 hkey_root = HKEY_LOCAL_MACHINE;
2418 cp = "";
2419 for (i = 0; i < nLines; ++i) {
2420 /* Ignore duplicate lines */
2421 if (strcmp(cp, lines[i])) {
2422 int ign;
2423 cp = lines[i];
2424 /* Parse the lines */
2425 if (2 == sscanf(cp, "%d Root Key: %s", &ign, &buffer)) {
2426 if (strcmp(buffer, "HKEY_CURRENT_USER")==0)
2427 hkey_root = HKEY_CURRENT_USER;
2428 else {
2429 // HKLM - check they have permissions.
2430 if (!HasLocalMachinePrivs()) {
2431 MessageBox(GetFocus(),
2432 "You do not seem to have sufficient access rights\n"
2433 "on this machine to uninstall this software",
2434 NULL,
2435 MB_OK | MB_ICONSTOP);
2436 return 1; /* Error */
2439 } else if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
2440 if (MyRemoveDirectory(cp))
2441 ++nDirs;
2442 else {
2443 int code = GetLastError();
2444 if (code != 2 && code != 3) { /* file or path not found */
2445 ++nErrors;
2448 } else if (2 == sscanf(cp, "%d File Copy: %s", &ign, &buffer)) {
2449 if (MyDeleteFile(cp))
2450 ++nFiles;
2451 else {
2452 int code = GetLastError();
2453 if (code != 2 && code != 3) { /* file or path not found */
2454 ++nErrors;
2457 } else if (2 == sscanf(cp, "%d File Overwrite: %s", &ign, &buffer)) {
2458 if (MyDeleteFile(cp))
2459 ++nFiles;
2460 else {
2461 int code = GetLastError();
2462 if (code != 2 && code != 3) { /* file or path not found */
2463 ++nErrors;
2466 } else if (2 == sscanf(cp, "%d Reg DB Key: %s", &ign, &buffer)) {
2467 DeleteRegistryKey(cp);
2468 } else if (2 == sscanf(cp, "%d Reg DB Value: %s", &ign, &buffer)) {
2469 DeleteRegistryValue(cp);
2470 } else if (2 == sscanf(cp, "%d Run Script: %s", &ign, &buffer)) {
2471 Run_RemoveScript(cp);
2476 if (DeleteFile(argv[2])) {
2477 ++nFiles;
2478 } else {
2479 ++nErrors;
2480 SystemError(GetLastError(), argv[2]);
2482 if (nErrors)
2483 wsprintf(buffer,
2484 "%d files and %d directories removed\n"
2485 "%d files or directories could not be removed",
2486 nFiles, nDirs, nErrors);
2487 else
2488 wsprintf(buffer, "%d files and %d directories removed",
2489 nFiles, nDirs);
2490 MessageBox(NULL, buffer, "Uninstall Finished!",
2491 MB_OK | MB_ICONINFORMATION);
2492 remove_exe();
2493 return 0;
2496 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
2497 LPSTR lpszCmdLine, INT nCmdShow)
2499 extern int __argc;
2500 extern char **__argv;
2501 char *basename;
2503 GetModuleFileName(NULL, modulename, sizeof(modulename));
2505 /* Map the executable file to memory */
2506 arc_data = MapExistingFile(modulename, &arc_size);
2507 if (!arc_data) {
2508 SystemError(GetLastError(), "Could not open archive");
2509 return 1;
2512 /* OK. So this program can act as installer (self-extracting
2513 * zip-file, or as uninstaller when started with '-u logfile'
2514 * command line flags.
2516 * The installer is usually started without command line flags,
2517 * and the uninstaller is usually started with the '-u logfile'
2518 * flag. What to do if some innocent user double-clicks the
2519 * exe-file?
2520 * The following implements a defensive strategy...
2523 /* Try to extract the configuration data into a temporary file */
2524 if (ExtractInstallData(arc_data, arc_size, &exe_size,
2525 &ini_file, &pre_install_script))
2526 return DoInstall();
2528 if (!ini_file && __argc > 1) {
2529 return DoUninstall(__argc, __argv);
2533 basename = strrchr(modulename, '\\');
2534 if (basename)
2535 ++basename;
2537 /* Last guess about the purpose of this program */
2538 if (basename && (0 == strncmp(basename, "Remove", 6)))
2539 SystemError(0, "This program is normally started by windows");
2540 else
2541 SystemError(0, "Setup program invalid or damaged");
2542 return 1;