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