blob: be4be3790585e5fcfa77fdf4035d0f92a329949d [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];
Thomas Heller9cc5cb72004-12-01 18:18:08 +0000614 char subkey_name[80];
Thomas Heller48340392004-06-18 17:03:38 +0000615 LONG size = sizeof(fullpath);
616 HINSTANCE h = LoadLibrary(fname);
617 if (h)
618 return h;
Thomas Heller9cc5cb72004-12-01 18:18:08 +0000619 wsprintf(subkey_name,
Thomas Heller8992b9b2004-12-01 19:43:02 +0000620 "SOFTWARE\\Python\\PythonCore\\%d.%d\\InstallPath",
Thomas Heller9cc5cb72004-12-01 18:18:08 +0000621 py_major, py_minor);
622 if (ERROR_SUCCESS != RegQueryValue(HKEY_CURRENT_USER, subkey_name,
Thomas Heller48340392004-06-18 17:03:38 +0000623 fullpath, &size))
624 return NULL;
625 strcat(fullpath, "\\");
626 strcat(fullpath, fname);
627 return LoadLibrary(fullpath);
628}
629
Thomas Hellera19cdad2004-02-20 14:43:21 +0000630static int prepare_script_environment(HINSTANCE hPython)
631{
632 PyObject *mod;
633 DECLPROC(hPython, PyObject *, PyImport_ImportModule, (char *));
634 DECLPROC(hPython, int, PyObject_SetAttrString, (PyObject *, char *, PyObject *));
635 DECLPROC(hPython, PyObject *, PyObject_GetAttrString, (PyObject *, char *));
636 DECLPROC(hPython, PyObject *, PyCFunction_New, (PyMethodDef *, PyObject *));
637 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
638 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
639 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
640 if (!PyImport_ImportModule || !PyObject_GetAttrString ||
641 !PyObject_SetAttrString || !PyCFunction_New)
642 return 1;
643 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
644 return 1;
645
646 mod = PyImport_ImportModule("__builtin__");
647 if (mod) {
648 int i;
649 g_PyExc_ValueError = PyObject_GetAttrString(mod, "ValueError");
650 g_PyExc_OSError = PyObject_GetAttrString(mod, "OSError");
651 for (i = 0; i < DIM(meth); ++i) {
652 PyObject_SetAttrString(mod, meth[i].ml_name,
653 PyCFunction_New(&meth[i], NULL));
654 }
655 }
656 g_Py_BuildValue = Py_BuildValue;
657 g_PyArg_ParseTuple = PyArg_ParseTuple;
658 g_PyErr_Format = PyErr_Format;
659
660 return 0;
661}
662
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000663/*
664 * This function returns one of the following error codes:
665 * 1 if the Python-dll does not export the functions we need
666 * 2 if no install-script is specified in pathname
667 * 3 if the install-script file could not be opened
668 * the return value of PyRun_SimpleFile() otherwise,
669 * which is 0 if everything is ok, -1 if an exception had occurred
670 * in the install-script.
671 */
672
673static int
674run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
675{
676 DECLPROC(hPython, void, Py_Initialize, (void));
677 DECLPROC(hPython, int, PySys_SetArgv, (int, char **));
678 DECLPROC(hPython, int, PyRun_SimpleFile, (FILE *, char *));
679 DECLPROC(hPython, void, Py_Finalize, (void));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000680 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
681 DECLPROC(hPython, PyObject *, PyCFunction_New,
682 (PyMethodDef *, PyObject *));
683 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
684 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
685
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000686 int result = 0;
687 FILE *fp;
688
689 if (!Py_Initialize || !PySys_SetArgv
690 || !PyRun_SimpleFile || !Py_Finalize)
691 return 1;
692
Thomas Hellera19cdad2004-02-20 14:43:21 +0000693 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000694 return 1;
695
696 if (!PyCFunction_New || !PyArg_ParseTuple || !PyErr_Format)
697 return 1;
698
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000699 if (pathname == NULL || pathname[0] == '\0')
700 return 2;
701
702 fp = fopen(pathname, "r");
703 if (!fp) {
704 fprintf(stderr, "Could not open postinstall-script %s\n",
705 pathname);
706 return 3;
707 }
708
709 SetDlgItemText(hDialog, IDC_INFO, "Running Script...");
710
711 Py_Initialize();
712
Thomas Hellera19cdad2004-02-20 14:43:21 +0000713 prepare_script_environment(hPython);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000714 PySys_SetArgv(argc, argv);
715 result = PyRun_SimpleFile(fp, pathname);
716 Py_Finalize();
717
718 fclose(fp);
719
720 return result;
721}
722
Thomas Hellera19cdad2004-02-20 14:43:21 +0000723static int do_run_simple_script(HINSTANCE hPython, char *script)
724{
725 int rc;
726 DECLPROC(hPython, void, Py_Initialize, (void));
727 DECLPROC(hPython, void, Py_SetProgramName, (char *));
728 DECLPROC(hPython, void, Py_Finalize, (void));
729 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
730 DECLPROC(hPython, void, PyErr_Print, (void));
731
732 if (!Py_Initialize || !Py_SetProgramName || !Py_Finalize ||
733 !PyRun_SimpleString || !PyErr_Print)
734 return -1;
735
736 Py_SetProgramName(modulename);
737 Py_Initialize();
738 prepare_script_environment(hPython);
739 rc = PyRun_SimpleString(script);
740 if (rc)
741 PyErr_Print();
742 Py_Finalize();
743 return rc;
744}
745
746static int run_simple_script(char *script)
747{
748 int rc;
749 char *tempname;
750 HINSTANCE hPython;
Mark Hammondf9bfdd82004-07-02 23:53:16 +0000751 tempname = tempnam(NULL, NULL);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000752 freopen(tempname, "a", stderr);
753 freopen(tempname, "a", stdout);
754
Thomas Heller48340392004-06-18 17:03:38 +0000755 hPython = LoadPythonDll(pythondll);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000756 if (!hPython) {
757 set_failure_reason("Can't load Python for pre-install script");
758 return -1;
759 }
760 rc = do_run_simple_script(hPython, script);
761 FreeLibrary(hPython);
762 fflush(stderr);
763 fflush(stdout);
764 /* We only care about the output when we fail. If the script works
765 OK, then we discard it
766 */
767 if (rc) {
768 int err_buf_size;
769 char *err_buf;
770 const char *prefix = "Running the pre-installation script failed\r\n";
771 int prefix_len = strlen(prefix);
772 FILE *fp = fopen(tempname, "rb");
773 fseek(fp, 0, SEEK_END);
774 err_buf_size = ftell(fp);
775 fseek(fp, 0, SEEK_SET);
776 err_buf = malloc(prefix_len + err_buf_size + 1);
777 if (err_buf) {
778 int n;
779 strcpy(err_buf, prefix);
780 n = fread(err_buf+prefix_len, 1, err_buf_size, fp);
781 err_buf[prefix_len+n] = '\0';
782 fclose(fp);
783 set_failure_reason(err_buf);
784 free(err_buf);
785 } else {
786 set_failure_reason("Out of memory!");
787 }
788 }
789 remove(tempname);
790 return rc;
791}
792
793
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000794static BOOL SystemError(int error, char *msg)
795{
796 char Buffer[1024];
797 int n;
798
799 if (error) {
800 LPVOID lpMsgBuf;
801 FormatMessage(
802 FORMAT_MESSAGE_ALLOCATE_BUFFER |
803 FORMAT_MESSAGE_FROM_SYSTEM,
804 NULL,
805 error,
806 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
807 (LPSTR)&lpMsgBuf,
808 0,
809 NULL
810 );
811 strncpy(Buffer, lpMsgBuf, sizeof(Buffer));
812 LocalFree(lpMsgBuf);
813 } else
814 Buffer[0] = '\0';
815 n = lstrlen(Buffer);
816 _snprintf(Buffer+n, sizeof(Buffer)-n, msg);
817 MessageBox(hwndMain, Buffer, "Runtime Error", MB_OK | MB_ICONSTOP);
818 return FALSE;
819}
820
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000821static BOOL notify (int code, char *fmt, ...)
822{
823 char Buffer[1024];
824 va_list marker;
825 BOOL result = TRUE;
826 int a, b;
827 char *cp;
828
829 va_start(marker, fmt);
830 _vsnprintf(Buffer, sizeof(Buffer), fmt, marker);
831
832 switch (code) {
833/* Questions */
834 case CAN_OVERWRITE:
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000835 break;
836
837/* Information notification */
838 case DIR_CREATED:
839 if (logfile)
840 fprintf(logfile, "100 Made Dir: %s\n", fmt);
841 break;
842
843 case FILE_CREATED:
844 if (logfile)
845 fprintf(logfile, "200 File Copy: %s\n", fmt);
846 goto add_to_filelist_label;
847 break;
848
849 case FILE_OVERWRITTEN:
850 if (logfile)
851 fprintf(logfile, "200 File Overwrite: %s\n", fmt);
852 add_to_filelist_label:
853 if ((cp = strrchr(fmt, '.')) && (0 == strcmp (cp, ".py")))
854 add_to_filelist(fmt);
855 break;
856
857/* Error Messages */
858 case ZLIB_ERROR:
859 MessageBox(GetFocus(), Buffer, "Error",
860 MB_OK | MB_ICONWARNING);
861 break;
862
863 case SYSTEM_ERROR:
864 SystemError(GetLastError(), Buffer);
865 break;
866
867 case NUM_FILES:
868 a = va_arg(marker, int);
869 b = va_arg(marker, int);
870 SendMessage(hDialog, WM_NUMFILES, 0, MAKELPARAM(0, a));
871 SendMessage(hDialog, WM_NEXTFILE, b,(LPARAM)fmt);
872 }
873 va_end(marker);
874
875 return result;
876}
877
878static char *MapExistingFile(char *pathname, DWORD *psize)
879{
880 HANDLE hFile, hFileMapping;
881 DWORD nSizeLow, nSizeHigh;
882 char *data;
883
884 hFile = CreateFile(pathname,
885 GENERIC_READ, FILE_SHARE_READ, NULL,
886 OPEN_EXISTING,
887 FILE_ATTRIBUTE_NORMAL, NULL);
888 if (hFile == INVALID_HANDLE_VALUE)
889 return NULL;
890 nSizeLow = GetFileSize(hFile, &nSizeHigh);
891 hFileMapping = CreateFileMapping(hFile,
892 NULL, PAGE_READONLY, 0, 0, NULL);
893 CloseHandle(hFile);
894
895 if (hFileMapping == INVALID_HANDLE_VALUE)
896 return NULL;
897
898 data = MapViewOfFile(hFileMapping,
899 FILE_MAP_READ, 0, 0, 0);
900
901 CloseHandle(hFileMapping);
902 *psize = nSizeLow;
903 return data;
904}
905
906
907static void create_bitmap(HWND hwnd)
908{
909 BITMAPFILEHEADER *bfh;
910 BITMAPINFO *bi;
911 HDC hdc;
912
913 if (!bitmap_bytes)
914 return;
915
916 if (hBitmap)
917 return;
918
919 hdc = GetDC(hwnd);
920
921 bfh = (BITMAPFILEHEADER *)bitmap_bytes;
922 bi = (BITMAPINFO *)(bitmap_bytes + sizeof(BITMAPFILEHEADER));
923
924 hBitmap = CreateDIBitmap(hdc,
925 &bi->bmiHeader,
926 CBM_INIT,
927 bitmap_bytes + bfh->bfOffBits,
928 bi,
929 DIB_RGB_COLORS);
930 ReleaseDC(hwnd, hdc);
931}
932
Thomas Hellera19cdad2004-02-20 14:43:21 +0000933/* Extract everything we need to begin the installation. Currently this
934 is the INI filename with install data, and the raw pre-install script
935*/
936static BOOL ExtractInstallData(char *data, DWORD size, int *pexe_size,
937 char **out_ini_file, char **out_preinstall_script)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000938{
939 /* read the end of central directory record */
940 struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
941 (struct eof_cdir)];
942
943 int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
944 pe->ofsCDir;
945
946 int ofs = arc_start - sizeof (struct meta_data_hdr);
947
948 /* read meta_data info */
949 struct meta_data_hdr *pmd = (struct meta_data_hdr *)&data[ofs];
950 char *src, *dst;
951 char *ini_file;
952 char tempdir[MAX_PATH];
953
Thomas Hellera19cdad2004-02-20 14:43:21 +0000954 /* ensure that if we fail, we don't have garbage out pointers */
955 *out_ini_file = *out_preinstall_script = NULL;
956
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000957 if (pe->tag != 0x06054b50) {
Thomas Hellera19cdad2004-02-20 14:43:21 +0000958 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000959 }
960
Thomas Heller876d9902004-07-19 09:57:58 +0000961 if (pmd->tag != 0x1234567B) {
962 return SystemError(0,
963 "Invalid cfgdata magic number (see bdist_wininst.py)");
964 }
965 if (ofs < 0) {
Thomas Hellera19cdad2004-02-20 14:43:21 +0000966 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000967 }
968
969 if (pmd->bitmap_size) {
970 /* Store pointer to bitmap bytes */
971 bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
972 }
973
974 *pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
975
976 src = ((char *)pmd) - pmd->uncomp_size;
977 ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
978 if (!ini_file)
Thomas Hellera19cdad2004-02-20 14:43:21 +0000979 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000980 if (!GetTempPath(sizeof(tempdir), tempdir)
981 || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
982 SystemError(GetLastError(),
983 "Could not create temporary file");
Thomas Hellera19cdad2004-02-20 14:43:21 +0000984 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000985 }
986
987 dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
988 0, 0, NULL/*notify*/);
989 if (!dst)
Thomas Hellera19cdad2004-02-20 14:43:21 +0000990 return FALSE;
991 /* Up to the first \0 is the INI file data. */
992 strncpy(dst, src, pmd->uncomp_size);
993 src += strlen(dst) + 1;
994 /* Up to next \0 is the pre-install script */
995 *out_preinstall_script = strdup(src);
996 *out_ini_file = ini_file;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000997 UnmapViewOfFile(dst);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000998 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000999}
1000
1001static void PumpMessages(void)
1002{
1003 MSG msg;
1004 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1005 TranslateMessage(&msg);
1006 DispatchMessage(&msg);
1007 }
1008}
1009
1010LRESULT CALLBACK
1011WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1012{
1013 HDC hdc;
1014 HFONT hFont;
1015 int h;
1016 PAINTSTRUCT ps;
1017 switch (msg) {
1018 case WM_PAINT:
1019 hdc = BeginPaint(hwnd, &ps);
1020 h = GetSystemMetrics(SM_CYSCREEN) / 10;
1021 hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
1022 0, 0, 0, 0, 0, 0, 0, "Times Roman");
1023 hFont = SelectObject(hdc, hFont);
1024 SetBkMode(hdc, TRANSPARENT);
1025 TextOut(hdc, 15, 15, title, strlen(title));
1026 SetTextColor(hdc, RGB(255, 255, 255));
1027 TextOut(hdc, 10, 10, title, strlen(title));
1028 DeleteObject(SelectObject(hdc, hFont));
1029 EndPaint(hwnd, &ps);
1030 return 0;
1031 }
1032 return DefWindowProc(hwnd, msg, wParam, lParam);
1033}
1034
1035static HWND CreateBackground(char *title)
1036{
1037 WNDCLASS wc;
1038 HWND hwnd;
1039 char buffer[4096];
1040
1041 wc.style = CS_VREDRAW | CS_HREDRAW;
1042 wc.lpfnWndProc = WindowProc;
1043 wc.cbWndExtra = 0;
1044 wc.cbClsExtra = 0;
1045 wc.hInstance = GetModuleHandle(NULL);
1046 wc.hIcon = NULL;
1047 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1048 wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
1049 wc.lpszMenuName = NULL;
1050 wc.lpszClassName = "SetupWindowClass";
1051
1052 if (!RegisterClass(&wc))
1053 MessageBox(hwndMain,
1054 "Could not register window class",
1055 "Setup.exe", MB_OK);
1056
1057 wsprintf(buffer, "Setup %s", title);
1058 hwnd = CreateWindow("SetupWindowClass",
1059 buffer,
1060 0,
1061 0, 0,
1062 GetSystemMetrics(SM_CXFULLSCREEN),
1063 GetSystemMetrics(SM_CYFULLSCREEN),
1064 NULL,
1065 NULL,
1066 GetModuleHandle(NULL),
1067 NULL);
1068 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
1069 UpdateWindow(hwnd);
1070 return hwnd;
1071}
1072
1073/*
1074 * Center a window on the screen
1075 */
1076static void CenterWindow(HWND hwnd)
1077{
1078 RECT rc;
1079 int w, h;
1080
1081 GetWindowRect(hwnd, &rc);
1082 w = GetSystemMetrics(SM_CXSCREEN);
1083 h = GetSystemMetrics(SM_CYSCREEN);
1084 MoveWindow(hwnd,
1085 (w - (rc.right-rc.left))/2,
1086 (h - (rc.bottom-rc.top))/2,
1087 rc.right-rc.left, rc.bottom-rc.top, FALSE);
1088}
1089
1090#include <prsht.h>
1091
1092BOOL CALLBACK
1093IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1094{
1095 LPNMHDR lpnm;
1096 char Buffer[4096];
1097
1098 switch (msg) {
1099 case WM_INITDIALOG:
1100 create_bitmap(hwnd);
1101 if(hBitmap)
1102 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1103 IMAGE_BITMAP, (LPARAM)hBitmap);
1104 CenterWindow(GetParent(hwnd));
1105 wsprintf(Buffer,
1106 "This Wizard will install %s on your computer. "
1107 "Click Next to continue "
1108 "or Cancel to exit the Setup Wizard.",
1109 meta_name);
1110 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1111 SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
1112 SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
1113 return FALSE;
1114
1115 case WM_NOTIFY:
1116 lpnm = (LPNMHDR) lParam;
1117
1118 switch (lpnm->code) {
1119 case PSN_SETACTIVE:
1120 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
1121 break;
1122
1123 case PSN_WIZNEXT:
1124 break;
1125
1126 case PSN_RESET:
1127 break;
1128
1129 default:
1130 break;
1131 }
1132 }
1133 return FALSE;
1134}
1135
1136#ifdef USE_OTHER_PYTHON_VERSIONS
1137/* These are really private variables used to communicate
1138 * between StatusRoutine and CheckPythonExe
1139 */
1140char bound_image_dll[_MAX_PATH];
1141int bound_image_major;
1142int bound_image_minor;
1143
1144static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
1145 PSTR ImageName,
1146 PSTR DllName,
1147 ULONG Va,
1148 ULONG Parameter)
1149{
1150 char fname[_MAX_PATH];
1151 int int_version;
1152
1153 switch(reason) {
1154 case BindOutOfMemory:
1155 case BindRvaToVaFailed:
1156 case BindNoRoomInImage:
1157 case BindImportProcedureFailed:
1158 break;
1159
1160 case BindImportProcedure:
1161 case BindForwarder:
1162 case BindForwarderNOT:
1163 case BindImageModified:
1164 case BindExpandFileHeaders:
1165 case BindImageComplete:
1166 case BindSymbolsNotUpdated:
1167 case BindMismatchedSymbols:
1168 case BindImportModuleFailed:
1169 break;
1170
1171 case BindImportModule:
1172 if (1 == sscanf(DllName, "python%d", &int_version)) {
1173 SearchPath(NULL, DllName, NULL, sizeof(fname),
1174 fname, NULL);
1175 strcpy(bound_image_dll, fname);
1176 bound_image_major = int_version / 10;
1177 bound_image_minor = int_version % 10;
1178 OutputDebugString("BOUND ");
1179 OutputDebugString(fname);
1180 OutputDebugString("\n");
1181 }
1182 break;
1183 }
1184 return TRUE;
1185}
1186
1187/*
1188 */
1189static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1190{
1191 void (__cdecl * Py_Initialize)(void);
1192 void (__cdecl * Py_SetProgramName)(char *);
1193 void (__cdecl * Py_Finalize)(void);
1194 void* (__cdecl * PySys_GetObject)(char *);
1195 void (__cdecl * PySys_SetArgv)(int, char **);
1196 char* (__cdecl * Py_GetPrefix)(void);
1197 char* (__cdecl * Py_GetPath)(void);
1198 HINSTANCE hPython;
1199 LPSTR prefix = NULL;
1200 int (__cdecl * PyRun_SimpleString)(char *);
1201
1202 {
1203 char Buffer[256];
1204 wsprintf(Buffer, "PYTHONHOME=%s", exe);
1205 *strrchr(Buffer, '\\') = '\0';
1206// MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1207 _putenv(Buffer);
1208 _putenv("PYTHONPATH=");
1209 }
1210
1211 hPython = LoadLibrary(dll);
1212 if (!hPython)
1213 return NULL;
1214 Py_Initialize = (void (*)(void))GetProcAddress
1215 (hPython,"Py_Initialize");
1216
1217 PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1218 (hPython,"PySys_SetArgv");
1219
1220 PyRun_SimpleString = (int (*)(char *))GetProcAddress
1221 (hPython,"PyRun_SimpleString");
1222
1223 Py_SetProgramName = (void (*)(char *))GetProcAddress
1224 (hPython,"Py_SetProgramName");
1225
1226 PySys_GetObject = (void* (*)(char *))GetProcAddress
1227 (hPython,"PySys_GetObject");
1228
1229 Py_GetPrefix = (char * (*)(void))GetProcAddress
1230 (hPython,"Py_GetPrefix");
1231
1232 Py_GetPath = (char * (*)(void))GetProcAddress
1233 (hPython,"Py_GetPath");
1234
1235 Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1236 "Py_Finalize");
1237 Py_SetProgramName(exe);
1238 Py_Initialize();
1239 PySys_SetArgv(1, &exe);
1240
1241 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1242 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
1243
1244 Py_Finalize();
1245 FreeLibrary(hPython);
1246
1247 return prefix;
1248}
1249
1250static BOOL
1251CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1252{
1253 bound_image_dll[0] = '\0';
1254 if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1255 pathname,
1256 NULL,
1257 NULL,
1258 StatusRoutine))
1259 return SystemError(0, "Could not bind image");
1260 if (bound_image_dll[0] == '\0')
1261 return SystemError(0, "Does not seem to be a python executable");
1262 *pmajor = bound_image_major;
1263 *pminor = bound_image_minor;
1264 if (version && *version) {
1265 char core_version[12];
1266 wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1267 if (strcmp(version, core_version))
1268 return SystemError(0, "Wrong Python version");
1269 }
1270 get_sys_prefix(pathname, bound_image_dll);
1271 return TRUE;
1272}
1273
1274/*
1275 * Browse for other python versions. Insert it into the listbox specified
1276 * by hwnd. version, if not NULL or empty, is the version required.
1277 */
1278static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1279{
1280 char vers_name[_MAX_PATH + 80];
1281 DWORD itemindex;
1282 OPENFILENAME of;
1283 char pathname[_MAX_PATH];
1284 DWORD result;
1285
1286 strcpy(pathname, "python.exe");
1287
1288 memset(&of, 0, sizeof(of));
1289 of.lStructSize = sizeof(OPENFILENAME);
1290 of.hwndOwner = GetParent(hwnd);
1291 of.hInstance = NULL;
1292 of.lpstrFilter = "python.exe\0python.exe\0";
1293 of.lpstrCustomFilter = NULL;
1294 of.nMaxCustFilter = 0;
1295 of.nFilterIndex = 1;
1296 of.lpstrFile = pathname;
1297 of.nMaxFile = sizeof(pathname);
1298 of.lpstrFileTitle = NULL;
1299 of.nMaxFileTitle = 0;
1300 of.lpstrInitialDir = NULL;
1301 of.lpstrTitle = "Python executable";
1302 of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1303 of.lpstrDefExt = "exe";
1304
1305 result = GetOpenFileName(&of);
1306 if (result) {
1307 int major, minor;
1308 if (!CheckPythonExe(pathname, version, &major, &minor)) {
1309 return FALSE;
1310 }
1311 *strrchr(pathname, '\\') = '\0';
1312 wsprintf(vers_name, "Python Version %d.%d in %s",
1313 major, minor, pathname);
1314 itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1315 (LPARAM)(LPSTR)vers_name);
1316 SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1317 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1318 (LPARAM)(LPSTR)strdup(pathname));
1319 return TRUE;
1320 }
1321 return FALSE;
1322}
1323#endif /* USE_OTHER_PYTHON_VERSIONS */
1324
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001325typedef struct _InstalledVersionInfo {
1326 char prefix[MAX_PATH+1]; // sys.prefix directory.
1327 HKEY hkey; // Is this Python in HKCU or HKLM?
1328} InstalledVersionInfo;
1329
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001330
1331/*
1332 * Fill the listbox specified by hwnd with all python versions found
1333 * in the registry. version, if not NULL or empty, is the version
1334 * required.
1335 */
1336static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1337{
1338 DWORD index = 0;
1339 char core_version[80];
1340 HKEY hKey;
1341 BOOL result = TRUE;
1342 DWORD bufsize;
1343
1344 if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1345 "Software\\Python\\PythonCore",
1346 0, KEY_READ, &hKey))
1347 return FALSE;
1348 bufsize = sizeof(core_version);
1349 while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1350 core_version, &bufsize, NULL,
1351 NULL, NULL, NULL)) {
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001352 char subkey_name[80], vers_name[80];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001353 int itemindex;
1354 DWORD value_size;
1355 HKEY hk;
1356
1357 bufsize = sizeof(core_version);
1358 ++index;
1359 if (version && *version && strcmp(version, core_version))
1360 continue;
1361
1362 wsprintf(vers_name, "Python Version %s (found in registry)",
1363 core_version);
1364 wsprintf(subkey_name,
1365 "Software\\Python\\PythonCore\\%s\\InstallPath",
1366 core_version);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001367 if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001368 InstalledVersionInfo *ivi =
1369 (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
1370 value_size = sizeof(ivi->prefix);
1371 if (ivi &&
1372 ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
1373 ivi->prefix, &value_size)) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001374 itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001375 (LPARAM)(LPSTR)vers_name);
1376 ivi->hkey = hkRoot;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001377 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001378 (LPARAM)(LPSTR)ivi);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001379 }
1380 RegCloseKey(hk);
1381 }
1382 }
1383 RegCloseKey(hKey);
1384 return result;
1385}
1386
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001387/* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1388BOOL HasLocalMachinePrivs()
1389{
1390 HKEY hKey;
1391 DWORD result;
1392 static char KeyName[] =
1393 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1394
1395 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1396 KeyName,
1397 0,
1398 KEY_CREATE_SUB_KEY,
1399 &hKey);
1400 if (result==0)
1401 RegCloseKey(hKey);
1402 return result==0;
1403}
1404
1405// Check the root registry key to use - either HKLM or HKCU.
1406// If Python is installed in HKCU, then our extension also must be installed
1407// in HKCU - as Python won't be available for other users, we shouldn't either
1408// (and will fail if we are!)
1409// If Python is installed in HKLM, then we will also prefer to use HKLM, but
1410// this may not be possible - so we silently fall back to HKCU.
1411//
1412// We assume hkey_root is already set to where Python itself is installed.
1413void CheckRootKey(HWND hwnd)
1414{
1415 if (hkey_root==HKEY_CURRENT_USER) {
1416 ; // as above, always install ourself in HKCU too.
1417 } else if (hkey_root==HKEY_LOCAL_MACHINE) {
1418 // Python in HKLM, but we may or may not have permissions there.
1419 // Open the uninstall key with 'create' permissions - if this fails,
1420 // we don't have permission.
1421 if (!HasLocalMachinePrivs())
1422 hkey_root = HKEY_CURRENT_USER;
1423 } else {
1424 MessageBox(hwnd, "Don't know Python's installation type",
1425 "Strange", MB_OK | MB_ICONSTOP);
1426 /* Default to wherever they can, but preferring HKLM */
1427 hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1428 }
1429}
1430
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001431/* Return the installation scheme depending on Python version number */
1432SCHEME *GetScheme(int major, int minor)
1433{
1434 if (major > 2)
1435 return new_scheme;
1436 else if((major == 2) && (minor >= 2))
1437 return new_scheme;
1438 return old_scheme;
1439}
1440
1441BOOL CALLBACK
1442SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1443{
1444 LPNMHDR lpnm;
1445
1446 switch (msg) {
1447 case WM_INITDIALOG:
1448 if (hBitmap)
1449 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1450 IMAGE_BITMAP, (LPARAM)hBitmap);
1451 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1452 HKEY_LOCAL_MACHINE, target_version);
1453 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1454 HKEY_CURRENT_USER, target_version);
1455 { /* select the last entry which is the highest python
1456 version found */
1457 int count;
1458 count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1459 LB_GETCOUNT, 0, 0);
1460 if (count && count != LB_ERR)
1461 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1462 count-1, 0);
1463
1464 /* If a specific Python version is required,
1465 * display a prominent notice showing this fact.
1466 */
1467 if (target_version && target_version[0]) {
1468 char buffer[4096];
1469 wsprintf(buffer,
1470 "Python %s is required for this package. "
1471 "Select installation to use:",
1472 target_version);
1473 SetDlgItemText(hwnd, IDC_TITLE, buffer);
1474 }
1475
1476 if (count == 0) {
1477 char Buffer[4096];
1478 char *msg;
1479 if (target_version && target_version[0]) {
1480 wsprintf(Buffer,
1481 "Python version %s required, which was not found"
1482 " in the registry.", target_version);
1483 msg = Buffer;
1484 } else
1485 msg = "No Python installation found in the registry.";
1486 MessageBox(hwnd, msg, "Cannot install",
1487 MB_OK | MB_ICONSTOP);
1488 }
1489 }
1490 goto UpdateInstallDir;
1491 break;
1492
1493 case WM_COMMAND:
1494 switch (LOWORD(wParam)) {
1495/*
1496 case IDC_OTHERPYTHON:
1497 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1498 target_version))
1499 goto UpdateInstallDir;
1500 break;
1501*/
1502 case IDC_VERSIONS_LIST:
1503 switch (HIWORD(wParam)) {
1504 int id;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001505 case LBN_SELCHANGE:
1506 UpdateInstallDir:
1507 PropSheet_SetWizButtons(GetParent(hwnd),
1508 PSWIZB_BACK | PSWIZB_NEXT);
1509 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1510 LB_GETCURSEL, 0, 0);
1511 if (id == LB_ERR) {
1512 PropSheet_SetWizButtons(GetParent(hwnd),
1513 PSWIZB_BACK);
1514 SetDlgItemText(hwnd, IDC_PATH, "");
1515 SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1516 strcpy(python_dir, "");
1517 strcpy(pythondll, "");
1518 } else {
1519 char *pbuf;
1520 int result;
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001521 InstalledVersionInfo *ivi;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001522 PropSheet_SetWizButtons(GetParent(hwnd),
1523 PSWIZB_BACK | PSWIZB_NEXT);
1524 /* Get the python directory */
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001525 ivi = (InstalledVersionInfo *)
1526 SendDlgItemMessage(hwnd,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001527 IDC_VERSIONS_LIST,
1528 LB_GETITEMDATA,
1529 id,
1530 0);
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001531 hkey_root = ivi->hkey;
1532 strcpy(python_dir, ivi->prefix);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001533 SetDlgItemText(hwnd, IDC_PATH, python_dir);
1534 /* retrieve the python version and pythondll to use */
1535 result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1536 LB_GETTEXTLEN, (WPARAM)id, 0);
1537 pbuf = (char *)malloc(result + 1);
1538 if (pbuf) {
1539 /* guess the name of the python-dll */
1540 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1541 LB_GETTEXT, (WPARAM)id,
1542 (LPARAM)pbuf);
1543 result = sscanf(pbuf, "Python Version %d.%d",
1544 &py_major, &py_minor);
Thomas Heller96142192004-04-15 18:19:02 +00001545 if (result == 2) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001546#ifdef _DEBUG
Thomas Hellera19cdad2004-02-20 14:43:21 +00001547 wsprintf(pythondll, "python%d%d_d.dll",
Thomas Heller96142192004-04-15 18:19:02 +00001548 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001549#else
Thomas Heller96142192004-04-15 18:19:02 +00001550 wsprintf(pythondll, "python%d%d.dll",
1551 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001552#endif
Thomas Heller96142192004-04-15 18:19:02 +00001553 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001554 free(pbuf);
1555 } else
1556 strcpy(pythondll, "");
1557 /* retrieve the scheme for this version */
1558 {
1559 char install_path[_MAX_PATH];
1560 SCHEME *scheme = GetScheme(py_major, py_minor);
1561 strcpy(install_path, python_dir);
1562 if (install_path[strlen(install_path)-1] != '\\')
1563 strcat(install_path, "\\");
1564 strcat(install_path, scheme[0].prefix);
1565 SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1566 }
1567 }
1568 }
1569 break;
1570 }
1571 return 0;
1572
1573 case WM_NOTIFY:
1574 lpnm = (LPNMHDR) lParam;
1575
1576 switch (lpnm->code) {
1577 int id;
1578 case PSN_SETACTIVE:
1579 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1580 LB_GETCURSEL, 0, 0);
1581 if (id == LB_ERR)
1582 PropSheet_SetWizButtons(GetParent(hwnd),
1583 PSWIZB_BACK);
1584 else
1585 PropSheet_SetWizButtons(GetParent(hwnd),
1586 PSWIZB_BACK | PSWIZB_NEXT);
1587 break;
1588
1589 case PSN_WIZNEXT:
1590 break;
1591
1592 case PSN_WIZFINISH:
1593 break;
1594
1595 case PSN_RESET:
1596 break;
1597
1598 default:
1599 break;
1600 }
1601 }
1602 return 0;
1603}
1604
1605static BOOL OpenLogfile(char *dir)
1606{
1607 char buffer[_MAX_PATH+1];
1608 time_t ltime;
1609 struct tm *now;
1610 long result;
1611 HKEY hKey, hSubkey;
1612 char subkey_name[256];
1613 static char KeyName[] =
1614 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001615 const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
1616 "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001617 DWORD disposition;
1618
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001619 /* Use Create, as the Uninstall subkey may not exist under HKCU.
1620 Use CreateKeyEx, so we can specify a SAM specifying write access
1621 */
1622 result = RegCreateKeyEx(hkey_root,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001623 KeyName,
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001624 0, /* reserved */
1625 NULL, /* class */
1626 0, /* options */
1627 KEY_CREATE_SUB_KEY, /* sam */
1628 NULL, /* security */
1629 &hKey, /* result key */
1630 NULL); /* disposition */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001631 if (result != ERROR_SUCCESS) {
1632 if (result == ERROR_ACCESS_DENIED) {
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001633 /* This should no longer be able to happen - we have already
1634 checked if they have permissions in HKLM, and all users
1635 should have write access to HKCU.
1636 */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001637 MessageBox(GetFocus(),
1638 "You do not seem to have sufficient access rights\n"
1639 "on this machine to install this software",
1640 NULL,
1641 MB_OK | MB_ICONSTOP);
1642 return FALSE;
1643 } else {
1644 MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1645 }
1646 }
1647
1648 sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1649 logfile = fopen(buffer, "a");
1650 time(&ltime);
1651 now = localtime(&ltime);
1652 strftime(buffer, sizeof(buffer),
1653 "*** Installation started %Y/%m/%d %H:%M ***\n",
1654 localtime(&ltime));
1655 fprintf(logfile, buffer);
1656 fprintf(logfile, "Source: %s\n", modulename);
1657
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001658 /* Root key must be first entry processed by uninstaller. */
1659 fprintf(logfile, "999 Root Key: %s\n", root_name);
1660
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001661 sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
1662
1663 result = RegCreateKeyEx(hKey, subkey_name,
1664 0, NULL, 0,
1665 KEY_WRITE,
1666 NULL,
1667 &hSubkey,
1668 &disposition);
1669
1670 if (result != ERROR_SUCCESS)
1671 MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
1672
1673 RegCloseKey(hKey);
1674
1675 if (disposition == REG_CREATED_NEW_KEY)
1676 fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
1677
1678 sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
1679
1680 result = RegSetValueEx(hSubkey, "DisplayName",
1681 0,
1682 REG_SZ,
1683 buffer,
1684 strlen(buffer)+1);
1685
1686 if (result != ERROR_SUCCESS)
1687 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1688
1689 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1690 KeyName, subkey_name, "DisplayName", buffer);
1691
1692 {
1693 FILE *fp;
1694 sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1695 fp = fopen(buffer, "wb");
1696 fwrite(arc_data, exe_size, 1, fp);
1697 fclose(fp);
1698
1699 sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1700 dir, meta_name, dir, meta_name);
1701
1702 result = RegSetValueEx(hSubkey, "UninstallString",
1703 0,
1704 REG_SZ,
1705 buffer,
1706 strlen(buffer)+1);
1707
1708 if (result != ERROR_SUCCESS)
1709 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1710
1711 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1712 KeyName, subkey_name, "UninstallString", buffer);
1713 }
1714 return TRUE;
1715}
1716
1717static void CloseLogfile(void)
1718{
1719 char buffer[_MAX_PATH+1];
1720 time_t ltime;
1721 struct tm *now;
1722
1723 time(&ltime);
1724 now = localtime(&ltime);
1725 strftime(buffer, sizeof(buffer),
1726 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1727 localtime(&ltime));
1728 fprintf(logfile, buffer);
1729 if (logfile)
1730 fclose(logfile);
1731}
1732
1733BOOL CALLBACK
1734InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1735{
1736 LPNMHDR lpnm;
1737 char Buffer[4096];
1738 SCHEME *scheme;
1739
1740 switch (msg) {
1741 case WM_INITDIALOG:
1742 if (hBitmap)
1743 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1744 IMAGE_BITMAP, (LPARAM)hBitmap);
1745 wsprintf(Buffer,
1746 "Click Next to begin the installation of %s. "
1747 "If you want to review or change any of your "
1748 " installation settings, click Back. "
1749 "Click Cancel to exit the wizard.",
1750 meta_name);
1751 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
Thomas Hellera19cdad2004-02-20 14:43:21 +00001752 SetDlgItemText(hwnd, IDC_INFO, "Ready to install");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001753 break;
1754
1755 case WM_NUMFILES:
1756 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1757 PumpMessages();
1758 return TRUE;
1759
1760 case WM_NEXTFILE:
1761 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1762 0);
1763 SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1764 PumpMessages();
1765 return TRUE;
1766
1767 case WM_NOTIFY:
1768 lpnm = (LPNMHDR) lParam;
1769
1770 switch (lpnm->code) {
1771 case PSN_SETACTIVE:
1772 PropSheet_SetWizButtons(GetParent(hwnd),
1773 PSWIZB_BACK | PSWIZB_NEXT);
1774 break;
1775
1776 case PSN_WIZFINISH:
1777 break;
1778
1779 case PSN_WIZNEXT:
1780 /* Handle a Next button click here */
1781 hDialog = hwnd;
Thomas Hellera19cdad2004-02-20 14:43:21 +00001782 success = TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001783
Thomas Heller32b8f802004-07-02 08:02:40 +00001784 /* Disable the buttons while we work. Sending CANCELTOCLOSE has
1785 the effect of disabling the cancel button, which is a) as we
1786 do everything synchronously we can't cancel, and b) the next
1787 step is 'finished', when it is too late to cancel anyway.
1788 The next step being 'Finished' means we also don't need to
1789 restore the button state back */
1790 PropSheet_SetWizButtons(GetParent(hwnd), 0);
1791 SendMessage(GetParent(hwnd), PSM_CANCELTOCLOSE, 0, 0);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001792 /* Make sure the installation directory name ends in a */
1793 /* backslash */
1794 if (python_dir[strlen(python_dir)-1] != '\\')
1795 strcat(python_dir, "\\");
1796 /* Strip the trailing backslash again */
1797 python_dir[strlen(python_dir)-1] = '\0';
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001798
Thomas Heller9cc5cb72004-12-01 18:18:08 +00001799 CheckRootKey(hwnd);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001800
1801 if (!OpenLogfile(python_dir))
1802 break;
1803
1804/*
1805 * The scheme we have to use depends on the Python version...
1806 if sys.version < "2.2":
1807 WINDOWS_SCHEME = {
1808 'purelib': '$base',
1809 'platlib': '$base',
1810 'headers': '$base/Include/$dist_name',
1811 'scripts': '$base/Scripts',
1812 'data' : '$base',
1813 }
1814 else:
1815 WINDOWS_SCHEME = {
1816 'purelib': '$base/Lib/site-packages',
1817 'platlib': '$base/Lib/site-packages',
1818 'headers': '$base/Include/$dist_name',
1819 'scripts': '$base/Scripts',
1820 'data' : '$base',
1821 }
1822*/
1823 scheme = GetScheme(py_major, py_minor);
Thomas Hellera19cdad2004-02-20 14:43:21 +00001824 /* Run the pre-install script. */
1825 if (pre_install_script && *pre_install_script) {
1826 SetDlgItemText (hwnd, IDC_TITLE,
1827 "Running pre-installation script");
1828 run_simple_script(pre_install_script);
1829 }
1830 if (!success) {
1831 break;
1832 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001833 /* Extract all files from the archive */
1834 SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
Thomas Hellera19cdad2004-02-20 14:43:21 +00001835 if (!unzip_archive (scheme,
1836 python_dir, arc_data,
1837 arc_size, notify))
1838 set_failure_reason("Failed to unzip installation files");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001839 /* Compile the py-files */
Thomas Hellera19cdad2004-02-20 14:43:21 +00001840 if (success && pyc_compile) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001841 int errors;
1842 HINSTANCE hPython;
1843 SetDlgItemText(hwnd, IDC_TITLE,
1844 "Compiling files to .pyc...");
1845
1846 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
Thomas Heller48340392004-06-18 17:03:38 +00001847 hPython = LoadPythonDll(pythondll);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001848 if (hPython) {
1849 errors = compile_filelist(hPython, FALSE);
1850 FreeLibrary(hPython);
1851 }
1852 /* Compilation errors are intentionally ignored:
1853 * Python2.0 contains a bug which will result
1854 * in sys.path containing garbage under certain
1855 * circumstances, and an error message will only
1856 * confuse the user.
1857 */
1858 }
Thomas Hellera19cdad2004-02-20 14:43:21 +00001859 if (success && pyo_compile) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001860 int errors;
1861 HINSTANCE hPython;
1862 SetDlgItemText(hwnd, IDC_TITLE,
1863 "Compiling files to .pyo...");
1864
1865 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
Thomas Heller48340392004-06-18 17:03:38 +00001866 hPython = LoadPythonDll(pythondll);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001867 if (hPython) {
1868 errors = compile_filelist(hPython, TRUE);
1869 FreeLibrary(hPython);
1870 }
1871 /* Errors ignored: see above */
1872 }
1873
1874
1875 break;
1876
1877 case PSN_RESET:
1878 break;
1879
1880 default:
1881 break;
1882 }
1883 }
1884 return 0;
1885}
1886
1887
1888BOOL CALLBACK
1889FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1890{
1891 LPNMHDR lpnm;
1892
1893 switch (msg) {
1894 case WM_INITDIALOG:
1895 if (hBitmap)
1896 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1897 IMAGE_BITMAP, (LPARAM)hBitmap);
1898 if (!success)
Thomas Hellera19cdad2004-02-20 14:43:21 +00001899 SetDlgItemText(hwnd, IDC_INFO, get_failure_reason());
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001900
1901 /* async delay: will show the dialog box completely before
1902 the install_script is started */
1903 PostMessage(hwnd, WM_USER, 0, 0L);
1904 return TRUE;
1905
1906 case WM_USER:
1907
Thomas Hellera19cdad2004-02-20 14:43:21 +00001908 if (success && install_script && install_script[0]) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001909 char fname[MAX_PATH];
1910 char *tempname;
1911 FILE *fp;
1912 char buffer[4096];
1913 int n;
1914 HCURSOR hCursor;
1915 HINSTANCE hPython;
1916
1917 char *argv[3] = {NULL, "-install", NULL};
1918
1919 SetDlgItemText(hwnd, IDC_TITLE,
1920 "Please wait while running postinstall script...");
1921 strcpy(fname, python_dir);
1922 strcat(fname, "\\Scripts\\");
1923 strcat(fname, install_script);
1924
1925 if (logfile)
1926 fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
1927
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001928 tempname = tempnam(NULL, NULL);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001929
1930 if (!freopen(tempname, "a", stderr))
1931 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
1932 if (!freopen(tempname, "a", stdout))
1933 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
1934/*
1935 if (0 != setvbuf(stdout, NULL, _IONBF, 0))
1936 MessageBox(GetFocus(), "setvbuf stdout", NULL, MB_OK);
1937*/
1938 hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
1939
1940 argv[0] = fname;
1941
Thomas Heller48340392004-06-18 17:03:38 +00001942 hPython = LoadPythonDll(pythondll);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001943 if (hPython) {
1944 int result;
1945 result = run_installscript(hPython, fname, 2, argv);
1946 if (-1 == result) {
1947 fprintf(stderr, "*** run_installscript: internal error 0x%X ***\n", result);
1948 }
1949 FreeLibrary(hPython);
1950 } else {
1951 fprintf(stderr, "*** Could not load Python ***");
1952 }
1953 fflush(stderr);
1954 fflush(stdout);
1955
1956 fp = fopen(tempname, "rb");
1957 n = fread(buffer, 1, sizeof(buffer), fp);
1958 fclose(fp);
1959 remove(tempname);
1960
1961 buffer[n] = '\0';
1962
1963 SetDlgItemText(hwnd, IDC_INFO, buffer);
1964 SetDlgItemText(hwnd, IDC_TITLE,
1965 "Postinstall script finished.\n"
1966 "Click the Finish button to exit the Setup wizard.");
1967
1968 SetCursor(hCursor);
1969 CloseLogfile();
1970 }
1971
1972 return TRUE;
1973
1974 case WM_NOTIFY:
1975 lpnm = (LPNMHDR) lParam;
1976
1977 switch (lpnm->code) {
1978 case PSN_SETACTIVE: /* Enable the Finish button */
1979 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH);
1980 break;
1981
1982 case PSN_WIZNEXT:
1983 break;
1984
1985 case PSN_WIZFINISH:
1986 break;
1987
1988 case PSN_RESET:
1989 break;
1990
1991 default:
1992 break;
1993 }
1994 }
1995 return 0;
1996}
1997
1998void RunWizard(HWND hwnd)
1999{
2000 PROPSHEETPAGE psp = {0};
2001 HPROPSHEETPAGE ahpsp[4] = {0};
2002 PROPSHEETHEADER psh = {0};
2003
2004 /* Display module information */
2005 psp.dwSize = sizeof(psp);
2006 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2007 psp.hInstance = GetModuleHandle (NULL);
2008 psp.lParam = 0;
2009 psp.pfnDlgProc = IntroDlgProc;
2010 psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO);
2011
2012 ahpsp[0] = CreatePropertySheetPage(&psp);
2013
2014 /* Select python version to use */
2015 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2016 psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTPYTHON);
2017 psp.pfnDlgProc = SelectPythonDlgProc;
2018
2019 ahpsp[1] = CreatePropertySheetPage(&psp);
2020
2021 /* Install the files */
2022 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2023 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFILES);
2024 psp.pfnDlgProc = InstallFilesDlgProc;
2025
2026 ahpsp[2] = CreatePropertySheetPage(&psp);
2027
2028 /* Show success or failure */
2029 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2030 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHED);
2031 psp.pfnDlgProc = FinishedDlgProc;
2032
2033 ahpsp[3] = CreatePropertySheetPage(&psp);
2034
2035 /* Create the property sheet */
2036 psh.dwSize = sizeof(psh);
2037 psh.hInstance = GetModuleHandle(NULL);
2038 psh.hwndParent = hwnd;
2039 psh.phpage = ahpsp;
2040 psh.dwFlags = PSH_WIZARD/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
2041 psh.pszbmWatermark = NULL;
2042 psh.pszbmHeader = NULL;
2043 psh.nStartPage = 0;
2044 psh.nPages = 4;
2045
2046 PropertySheet(&psh);
2047}
2048
2049int DoInstall(void)
2050{
2051 char ini_buffer[4096];
2052
2053 /* Read installation information */
2054 GetPrivateProfileString("Setup", "title", "", ini_buffer,
2055 sizeof(ini_buffer), ini_file);
2056 unescape(title, ini_buffer, sizeof(title));
2057
2058 GetPrivateProfileString("Setup", "info", "", ini_buffer,
2059 sizeof(ini_buffer), ini_file);
2060 unescape(info, ini_buffer, sizeof(info));
2061
2062 GetPrivateProfileString("Setup", "build_info", "", build_info,
2063 sizeof(build_info), ini_file);
2064
2065 pyc_compile = GetPrivateProfileInt("Setup", "target_compile", 1,
2066 ini_file);
2067 pyo_compile = GetPrivateProfileInt("Setup", "target_optimize", 1,
2068 ini_file);
2069
2070 GetPrivateProfileString("Setup", "target_version", "",
2071 target_version, sizeof(target_version),
2072 ini_file);
2073
2074 GetPrivateProfileString("metadata", "name", "",
2075 meta_name, sizeof(meta_name),
2076 ini_file);
2077
2078 GetPrivateProfileString("Setup", "install_script", "",
2079 install_script, sizeof(install_script),
2080 ini_file);
2081
2082
2083 hwndMain = CreateBackground(title);
2084
2085 RunWizard(hwndMain);
2086
2087 /* Clean up */
2088 UnmapViewOfFile(arc_data);
2089 if (ini_file)
2090 DeleteFile(ini_file);
2091
2092 if (hBitmap)
2093 DeleteObject(hBitmap);
2094
2095 return 0;
2096}
2097
2098/*********************** uninstall section ******************************/
2099
2100static int compare(const void *p1, const void *p2)
2101{
2102 return strcmp(*(char **)p2, *(char **)p1);
2103}
2104
2105/*
2106 * Commit suicide (remove the uninstaller itself).
2107 *
2108 * Create a batch file to first remove the uninstaller
2109 * (will succeed after it has finished), then the batch file itself.
2110 *
2111 * This technique has been demonstrated by Jeff Richter,
2112 * MSJ 1/1996
2113 */
2114void remove_exe(void)
2115{
2116 char exename[_MAX_PATH];
2117 char batname[_MAX_PATH];
2118 FILE *fp;
2119 STARTUPINFO si;
2120 PROCESS_INFORMATION pi;
2121
2122 GetModuleFileName(NULL, exename, sizeof(exename));
2123 sprintf(batname, "%s.bat", exename);
2124 fp = fopen(batname, "w");
2125 fprintf(fp, ":Repeat\n");
2126 fprintf(fp, "del \"%s\"\n", exename);
2127 fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
2128 fprintf(fp, "del \"%s\"\n", batname);
2129 fclose(fp);
2130
2131 ZeroMemory(&si, sizeof(si));
2132 si.cb = sizeof(si);
2133 si.dwFlags = STARTF_USESHOWWINDOW;
2134 si.wShowWindow = SW_HIDE;
2135 if (CreateProcess(NULL,
2136 batname,
2137 NULL,
2138 NULL,
2139 FALSE,
2140 CREATE_SUSPENDED | IDLE_PRIORITY_CLASS,
2141 NULL,
2142 "\\",
2143 &si,
2144 &pi)) {
2145 SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE);
2146 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
2147 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
2148 CloseHandle(pi.hProcess);
2149 ResumeThread(pi.hThread);
2150 CloseHandle(pi.hThread);
2151 }
2152}
2153
2154void DeleteRegistryKey(char *string)
2155{
2156 char *keyname;
2157 char *subkeyname;
2158 char *delim;
2159 HKEY hKey;
2160 long result;
2161 char *line;
2162
2163 line = strdup(string); /* so we can change it */
2164
2165 keyname = strchr(line, '[');
2166 if (!keyname)
2167 return;
2168 ++keyname;
2169
2170 subkeyname = strchr(keyname, ']');
2171 if (!subkeyname)
2172 return;
2173 *subkeyname++='\0';
2174 delim = strchr(subkeyname, '\n');
2175 if (delim)
2176 *delim = '\0';
2177
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002178 result = RegOpenKeyEx(hkey_root,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002179 keyname,
2180 0,
2181 KEY_WRITE,
2182 &hKey);
2183
2184 if (result != ERROR_SUCCESS)
2185 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2186 else {
2187 result = RegDeleteKey(hKey, subkeyname);
Thomas Heller55a98642004-07-14 14:53:50 +00002188 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002189 MessageBox(GetFocus(), string, "Could not delete key", MB_OK);
2190 RegCloseKey(hKey);
2191 }
2192 free(line);
2193}
2194
2195void DeleteRegistryValue(char *string)
2196{
2197 char *keyname;
2198 char *valuename;
2199 char *value;
2200 HKEY hKey;
2201 long result;
2202 char *line;
2203
2204 line = strdup(string); /* so we can change it */
2205
2206/* Format is 'Reg DB Value: [key]name=value' */
2207 keyname = strchr(line, '[');
2208 if (!keyname)
2209 return;
2210 ++keyname;
2211 valuename = strchr(keyname, ']');
2212 if (!valuename)
2213 return;
2214 *valuename++ = '\0';
2215 value = strchr(valuename, '=');
2216 if (!value)
2217 return;
2218
2219 *value++ = '\0';
2220
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002221 result = RegOpenKeyEx(hkey_root,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002222 keyname,
2223 0,
2224 KEY_WRITE,
2225 &hKey);
2226 if (result != ERROR_SUCCESS)
2227 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2228 else {
2229 result = RegDeleteValue(hKey, valuename);
Thomas Heller55a98642004-07-14 14:53:50 +00002230 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002231 MessageBox(GetFocus(), string, "Could not delete value", MB_OK);
2232 RegCloseKey(hKey);
2233 }
2234 free(line);
2235}
2236
2237BOOL MyDeleteFile(char *line)
2238{
2239 char *pathname = strchr(line, ':');
2240 if (!pathname)
2241 return FALSE;
2242 ++pathname;
2243 while (isspace(*pathname))
2244 ++pathname;
2245 return DeleteFile(pathname);
2246}
2247
2248BOOL MyRemoveDirectory(char *line)
2249{
2250 char *pathname = strchr(line, ':');
2251 if (!pathname)
2252 return FALSE;
2253 ++pathname;
2254 while (isspace(*pathname))
2255 ++pathname;
2256 return RemoveDirectory(pathname);
2257}
2258
2259BOOL Run_RemoveScript(char *line)
2260{
2261 char *dllname;
2262 char *scriptname;
2263 static char lastscript[MAX_PATH];
2264
2265/* Format is 'Run Scripts: [pythondll]scriptname' */
2266/* XXX Currently, pythondll carries no path!!! */
2267 dllname = strchr(line, '[');
2268 if (!dllname)
2269 return FALSE;
2270 ++dllname;
2271 scriptname = strchr(dllname, ']');
2272 if (!scriptname)
2273 return FALSE;
2274 *scriptname++ = '\0';
2275 /* this function may be called more than one time with the same
2276 script, only run it one time */
2277 if (strcmp(lastscript, scriptname)) {
2278 HINSTANCE hPython;
2279 char *argv[3] = {NULL, "-remove", NULL};
2280 char buffer[4096];
2281 FILE *fp;
2282 char *tempname;
2283 int n;
2284
2285 argv[0] = scriptname;
2286
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002287 tempname = tempnam(NULL, NULL);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002288
2289 if (!freopen(tempname, "a", stderr))
2290 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
2291 if (!freopen(tempname, "a", stdout))
2292 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
2293
2294 hPython = LoadLibrary(dllname);
2295 if (hPython) {
2296 if (0x80000000 == run_installscript(hPython, scriptname, 2, argv))
2297 fprintf(stderr, "*** Could not load Python ***");
2298 FreeLibrary(hPython);
2299 }
2300
2301 fflush(stderr);
2302 fflush(stdout);
2303
2304 fp = fopen(tempname, "rb");
2305 n = fread(buffer, 1, sizeof(buffer), fp);
2306 fclose(fp);
2307 remove(tempname);
2308
2309 buffer[n] = '\0';
2310 if (buffer[0])
2311 MessageBox(GetFocus(), buffer, "uninstall-script", MB_OK);
2312
2313 strcpy(lastscript, scriptname);
2314 }
2315 return TRUE;
2316}
2317
2318int DoUninstall(int argc, char **argv)
2319{
2320 FILE *logfile;
2321 char buffer[4096];
2322 int nLines = 0;
2323 int i;
2324 char *cp;
2325 int nFiles = 0;
2326 int nDirs = 0;
2327 int nErrors = 0;
2328 char **lines;
2329 int lines_buffer_size = 10;
2330
2331 if (argc != 3) {
2332 MessageBox(NULL,
2333 "Wrong number of args",
2334 NULL,
2335 MB_OK);
2336 return 1; /* Error */
2337 }
2338 if (strcmp(argv[1], "-u")) {
2339 MessageBox(NULL,
2340 "2. arg is not -u",
2341 NULL,
2342 MB_OK);
2343 return 1; /* Error */
2344 }
2345
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002346 logfile = fopen(argv[2], "r");
2347 if (!logfile) {
2348 MessageBox(NULL,
2349 "could not open logfile",
2350 NULL,
2351 MB_OK);
2352 return 1; /* Error */
2353 }
2354
2355 lines = (char **)malloc(sizeof(char *) * lines_buffer_size);
2356 if (!lines)
2357 return SystemError(0, "Out of memory");
2358
2359 /* Read the whole logfile, realloacting the buffer */
2360 while (fgets(buffer, sizeof(buffer), logfile)) {
2361 int len = strlen(buffer);
2362 /* remove trailing white space */
2363 while (isspace(buffer[len-1]))
2364 len -= 1;
2365 buffer[len] = '\0';
2366 lines[nLines++] = strdup(buffer);
2367 if (nLines >= lines_buffer_size) {
2368 lines_buffer_size += 10;
2369 lines = (char **)realloc(lines,
2370 sizeof(char *) * lines_buffer_size);
2371 if (!lines)
2372 return SystemError(0, "Out of memory");
2373 }
2374 }
2375 fclose(logfile);
2376
2377 /* Sort all the lines, so that highest 3-digit codes are first */
2378 qsort(&lines[0], nLines, sizeof(char *),
2379 compare);
2380
2381 if (IDYES != MessageBox(NULL,
2382 "Are you sure you want to remove\n"
2383 "this package from your computer?",
2384 "Please confirm",
2385 MB_YESNO | MB_ICONQUESTION))
2386 return 0;
2387
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002388 hkey_root = HKEY_LOCAL_MACHINE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002389 cp = "";
2390 for (i = 0; i < nLines; ++i) {
2391 /* Ignore duplicate lines */
2392 if (strcmp(cp, lines[i])) {
2393 int ign;
2394 cp = lines[i];
2395 /* Parse the lines */
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002396 if (2 == sscanf(cp, "%d Root Key: %s", &ign, &buffer)) {
2397 if (strcmp(buffer, "HKEY_CURRENT_USER")==0)
2398 hkey_root = HKEY_CURRENT_USER;
2399 else {
2400 // HKLM - check they have permissions.
2401 if (!HasLocalMachinePrivs()) {
2402 MessageBox(GetFocus(),
2403 "You do not seem to have sufficient access rights\n"
2404 "on this machine to uninstall this software",
2405 NULL,
2406 MB_OK | MB_ICONSTOP);
2407 return 1; /* Error */
2408 }
2409 }
2410 } else if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002411 if (MyRemoveDirectory(cp))
2412 ++nDirs;
2413 else {
2414 int code = GetLastError();
2415 if (code != 2 && code != 3) { /* file or path not found */
2416 ++nErrors;
2417 }
2418 }
2419 } else if (2 == sscanf(cp, "%d File Copy: %s", &ign, &buffer)) {
2420 if (MyDeleteFile(cp))
2421 ++nFiles;
2422 else {
2423 int code = GetLastError();
2424 if (code != 2 && code != 3) { /* file or path not found */
2425 ++nErrors;
2426 }
2427 }
2428 } else if (2 == sscanf(cp, "%d File Overwrite: %s", &ign, &buffer)) {
2429 if (MyDeleteFile(cp))
2430 ++nFiles;
2431 else {
2432 int code = GetLastError();
2433 if (code != 2 && code != 3) { /* file or path not found */
2434 ++nErrors;
2435 }
2436 }
2437 } else if (2 == sscanf(cp, "%d Reg DB Key: %s", &ign, &buffer)) {
2438 DeleteRegistryKey(cp);
2439 } else if (2 == sscanf(cp, "%d Reg DB Value: %s", &ign, &buffer)) {
2440 DeleteRegistryValue(cp);
2441 } else if (2 == sscanf(cp, "%d Run Script: %s", &ign, &buffer)) {
2442 Run_RemoveScript(cp);
2443 }
2444 }
2445 }
2446
2447 if (DeleteFile(argv[2])) {
2448 ++nFiles;
2449 } else {
2450 ++nErrors;
2451 SystemError(GetLastError(), argv[2]);
2452 }
2453 if (nErrors)
2454 wsprintf(buffer,
2455 "%d files and %d directories removed\n"
2456 "%d files or directories could not be removed",
2457 nFiles, nDirs, nErrors);
2458 else
2459 wsprintf(buffer, "%d files and %d directories removed",
2460 nFiles, nDirs);
2461 MessageBox(NULL, buffer, "Uninstall Finished!",
2462 MB_OK | MB_ICONINFORMATION);
2463 remove_exe();
2464 return 0;
2465}
2466
2467int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
2468 LPSTR lpszCmdLine, INT nCmdShow)
2469{
2470 extern int __argc;
2471 extern char **__argv;
2472 char *basename;
2473
2474 GetModuleFileName(NULL, modulename, sizeof(modulename));
2475
2476 /* Map the executable file to memory */
2477 arc_data = MapExistingFile(modulename, &arc_size);
2478 if (!arc_data) {
2479 SystemError(GetLastError(), "Could not open archive");
2480 return 1;
2481 }
2482
2483 /* OK. So this program can act as installer (self-extracting
2484 * zip-file, or as uninstaller when started with '-u logfile'
2485 * command line flags.
2486 *
2487 * The installer is usually started without command line flags,
2488 * and the uninstaller is usually started with the '-u logfile'
2489 * flag. What to do if some innocent user double-clicks the
2490 * exe-file?
2491 * The following implements a defensive strategy...
2492 */
2493
2494 /* Try to extract the configuration data into a temporary file */
Thomas Hellera19cdad2004-02-20 14:43:21 +00002495 if (ExtractInstallData(arc_data, arc_size, &exe_size,
2496 &ini_file, &pre_install_script))
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002497 return DoInstall();
2498
2499 if (!ini_file && __argc > 1) {
2500 return DoUninstall(__argc, __argv);
2501 }
2502
2503
2504 basename = strrchr(modulename, '\\');
2505 if (basename)
2506 ++basename;
2507
2508 /* Last guess about the purpose of this program */
2509 if (basename && (0 == strncmp(basename, "Remove", 6)))
2510 SystemError(0, "This program is normally started by windows");
2511 else
2512 SystemError(0, "Setup program invalid or damaged");
2513 return 1;
2514}