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