blob: d268624e98d5e1cf08cdd5bbddd2570d67efec46 [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
Thomas Heller876d9902004-07-19 09:57:58 +0000958 if (pmd->tag != 0x1234567B) {
959 return SystemError(0,
960 "Invalid cfgdata magic number (see bdist_wininst.py)");
961 }
962 if (ofs < 0) {
Thomas Hellera19cdad2004-02-20 14:43:21 +0000963 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000964 }
965
966 if (pmd->bitmap_size) {
967 /* Store pointer to bitmap bytes */
968 bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
969 }
970
971 *pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
972
973 src = ((char *)pmd) - pmd->uncomp_size;
974 ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
975 if (!ini_file)
Thomas Hellera19cdad2004-02-20 14:43:21 +0000976 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000977 if (!GetTempPath(sizeof(tempdir), tempdir)
978 || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
979 SystemError(GetLastError(),
980 "Could not create temporary file");
Thomas Hellera19cdad2004-02-20 14:43:21 +0000981 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000982 }
983
984 dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
985 0, 0, NULL/*notify*/);
986 if (!dst)
Thomas Hellera19cdad2004-02-20 14:43:21 +0000987 return FALSE;
988 /* Up to the first \0 is the INI file data. */
989 strncpy(dst, src, pmd->uncomp_size);
990 src += strlen(dst) + 1;
991 /* Up to next \0 is the pre-install script */
992 *out_preinstall_script = strdup(src);
993 *out_ini_file = ini_file;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000994 UnmapViewOfFile(dst);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000995 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000996}
997
998static void PumpMessages(void)
999{
1000 MSG msg;
1001 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1002 TranslateMessage(&msg);
1003 DispatchMessage(&msg);
1004 }
1005}
1006
1007LRESULT CALLBACK
1008WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1009{
1010 HDC hdc;
1011 HFONT hFont;
1012 int h;
1013 PAINTSTRUCT ps;
1014 switch (msg) {
1015 case WM_PAINT:
1016 hdc = BeginPaint(hwnd, &ps);
1017 h = GetSystemMetrics(SM_CYSCREEN) / 10;
1018 hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
1019 0, 0, 0, 0, 0, 0, 0, "Times Roman");
1020 hFont = SelectObject(hdc, hFont);
1021 SetBkMode(hdc, TRANSPARENT);
1022 TextOut(hdc, 15, 15, title, strlen(title));
1023 SetTextColor(hdc, RGB(255, 255, 255));
1024 TextOut(hdc, 10, 10, title, strlen(title));
1025 DeleteObject(SelectObject(hdc, hFont));
1026 EndPaint(hwnd, &ps);
1027 return 0;
1028 }
1029 return DefWindowProc(hwnd, msg, wParam, lParam);
1030}
1031
1032static HWND CreateBackground(char *title)
1033{
1034 WNDCLASS wc;
1035 HWND hwnd;
1036 char buffer[4096];
1037
1038 wc.style = CS_VREDRAW | CS_HREDRAW;
1039 wc.lpfnWndProc = WindowProc;
1040 wc.cbWndExtra = 0;
1041 wc.cbClsExtra = 0;
1042 wc.hInstance = GetModuleHandle(NULL);
1043 wc.hIcon = NULL;
1044 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1045 wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
1046 wc.lpszMenuName = NULL;
1047 wc.lpszClassName = "SetupWindowClass";
1048
1049 if (!RegisterClass(&wc))
1050 MessageBox(hwndMain,
1051 "Could not register window class",
1052 "Setup.exe", MB_OK);
1053
1054 wsprintf(buffer, "Setup %s", title);
1055 hwnd = CreateWindow("SetupWindowClass",
1056 buffer,
1057 0,
1058 0, 0,
1059 GetSystemMetrics(SM_CXFULLSCREEN),
1060 GetSystemMetrics(SM_CYFULLSCREEN),
1061 NULL,
1062 NULL,
1063 GetModuleHandle(NULL),
1064 NULL);
1065 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
1066 UpdateWindow(hwnd);
1067 return hwnd;
1068}
1069
1070/*
1071 * Center a window on the screen
1072 */
1073static void CenterWindow(HWND hwnd)
1074{
1075 RECT rc;
1076 int w, h;
1077
1078 GetWindowRect(hwnd, &rc);
1079 w = GetSystemMetrics(SM_CXSCREEN);
1080 h = GetSystemMetrics(SM_CYSCREEN);
1081 MoveWindow(hwnd,
1082 (w - (rc.right-rc.left))/2,
1083 (h - (rc.bottom-rc.top))/2,
1084 rc.right-rc.left, rc.bottom-rc.top, FALSE);
1085}
1086
1087#include <prsht.h>
1088
1089BOOL CALLBACK
1090IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1091{
1092 LPNMHDR lpnm;
1093 char Buffer[4096];
1094
1095 switch (msg) {
1096 case WM_INITDIALOG:
1097 create_bitmap(hwnd);
1098 if(hBitmap)
1099 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1100 IMAGE_BITMAP, (LPARAM)hBitmap);
1101 CenterWindow(GetParent(hwnd));
1102 wsprintf(Buffer,
1103 "This Wizard will install %s on your computer. "
1104 "Click Next to continue "
1105 "or Cancel to exit the Setup Wizard.",
1106 meta_name);
1107 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1108 SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
1109 SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
1110 return FALSE;
1111
1112 case WM_NOTIFY:
1113 lpnm = (LPNMHDR) lParam;
1114
1115 switch (lpnm->code) {
1116 case PSN_SETACTIVE:
1117 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
1118 break;
1119
1120 case PSN_WIZNEXT:
1121 break;
1122
1123 case PSN_RESET:
1124 break;
1125
1126 default:
1127 break;
1128 }
1129 }
1130 return FALSE;
1131}
1132
1133#ifdef USE_OTHER_PYTHON_VERSIONS
1134/* These are really private variables used to communicate
1135 * between StatusRoutine and CheckPythonExe
1136 */
1137char bound_image_dll[_MAX_PATH];
1138int bound_image_major;
1139int bound_image_minor;
1140
1141static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
1142 PSTR ImageName,
1143 PSTR DllName,
1144 ULONG Va,
1145 ULONG Parameter)
1146{
1147 char fname[_MAX_PATH];
1148 int int_version;
1149
1150 switch(reason) {
1151 case BindOutOfMemory:
1152 case BindRvaToVaFailed:
1153 case BindNoRoomInImage:
1154 case BindImportProcedureFailed:
1155 break;
1156
1157 case BindImportProcedure:
1158 case BindForwarder:
1159 case BindForwarderNOT:
1160 case BindImageModified:
1161 case BindExpandFileHeaders:
1162 case BindImageComplete:
1163 case BindSymbolsNotUpdated:
1164 case BindMismatchedSymbols:
1165 case BindImportModuleFailed:
1166 break;
1167
1168 case BindImportModule:
1169 if (1 == sscanf(DllName, "python%d", &int_version)) {
1170 SearchPath(NULL, DllName, NULL, sizeof(fname),
1171 fname, NULL);
1172 strcpy(bound_image_dll, fname);
1173 bound_image_major = int_version / 10;
1174 bound_image_minor = int_version % 10;
1175 OutputDebugString("BOUND ");
1176 OutputDebugString(fname);
1177 OutputDebugString("\n");
1178 }
1179 break;
1180 }
1181 return TRUE;
1182}
1183
1184/*
1185 */
1186static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1187{
1188 void (__cdecl * Py_Initialize)(void);
1189 void (__cdecl * Py_SetProgramName)(char *);
1190 void (__cdecl * Py_Finalize)(void);
1191 void* (__cdecl * PySys_GetObject)(char *);
1192 void (__cdecl * PySys_SetArgv)(int, char **);
1193 char* (__cdecl * Py_GetPrefix)(void);
1194 char* (__cdecl * Py_GetPath)(void);
1195 HINSTANCE hPython;
1196 LPSTR prefix = NULL;
1197 int (__cdecl * PyRun_SimpleString)(char *);
1198
1199 {
1200 char Buffer[256];
1201 wsprintf(Buffer, "PYTHONHOME=%s", exe);
1202 *strrchr(Buffer, '\\') = '\0';
1203// MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1204 _putenv(Buffer);
1205 _putenv("PYTHONPATH=");
1206 }
1207
1208 hPython = LoadLibrary(dll);
1209 if (!hPython)
1210 return NULL;
1211 Py_Initialize = (void (*)(void))GetProcAddress
1212 (hPython,"Py_Initialize");
1213
1214 PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1215 (hPython,"PySys_SetArgv");
1216
1217 PyRun_SimpleString = (int (*)(char *))GetProcAddress
1218 (hPython,"PyRun_SimpleString");
1219
1220 Py_SetProgramName = (void (*)(char *))GetProcAddress
1221 (hPython,"Py_SetProgramName");
1222
1223 PySys_GetObject = (void* (*)(char *))GetProcAddress
1224 (hPython,"PySys_GetObject");
1225
1226 Py_GetPrefix = (char * (*)(void))GetProcAddress
1227 (hPython,"Py_GetPrefix");
1228
1229 Py_GetPath = (char * (*)(void))GetProcAddress
1230 (hPython,"Py_GetPath");
1231
1232 Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1233 "Py_Finalize");
1234 Py_SetProgramName(exe);
1235 Py_Initialize();
1236 PySys_SetArgv(1, &exe);
1237
1238 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1239 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
1240
1241 Py_Finalize();
1242 FreeLibrary(hPython);
1243
1244 return prefix;
1245}
1246
1247static BOOL
1248CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1249{
1250 bound_image_dll[0] = '\0';
1251 if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1252 pathname,
1253 NULL,
1254 NULL,
1255 StatusRoutine))
1256 return SystemError(0, "Could not bind image");
1257 if (bound_image_dll[0] == '\0')
1258 return SystemError(0, "Does not seem to be a python executable");
1259 *pmajor = bound_image_major;
1260 *pminor = bound_image_minor;
1261 if (version && *version) {
1262 char core_version[12];
1263 wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1264 if (strcmp(version, core_version))
1265 return SystemError(0, "Wrong Python version");
1266 }
1267 get_sys_prefix(pathname, bound_image_dll);
1268 return TRUE;
1269}
1270
1271/*
1272 * Browse for other python versions. Insert it into the listbox specified
1273 * by hwnd. version, if not NULL or empty, is the version required.
1274 */
1275static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1276{
1277 char vers_name[_MAX_PATH + 80];
1278 DWORD itemindex;
1279 OPENFILENAME of;
1280 char pathname[_MAX_PATH];
1281 DWORD result;
1282
1283 strcpy(pathname, "python.exe");
1284
1285 memset(&of, 0, sizeof(of));
1286 of.lStructSize = sizeof(OPENFILENAME);
1287 of.hwndOwner = GetParent(hwnd);
1288 of.hInstance = NULL;
1289 of.lpstrFilter = "python.exe\0python.exe\0";
1290 of.lpstrCustomFilter = NULL;
1291 of.nMaxCustFilter = 0;
1292 of.nFilterIndex = 1;
1293 of.lpstrFile = pathname;
1294 of.nMaxFile = sizeof(pathname);
1295 of.lpstrFileTitle = NULL;
1296 of.nMaxFileTitle = 0;
1297 of.lpstrInitialDir = NULL;
1298 of.lpstrTitle = "Python executable";
1299 of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1300 of.lpstrDefExt = "exe";
1301
1302 result = GetOpenFileName(&of);
1303 if (result) {
1304 int major, minor;
1305 if (!CheckPythonExe(pathname, version, &major, &minor)) {
1306 return FALSE;
1307 }
1308 *strrchr(pathname, '\\') = '\0';
1309 wsprintf(vers_name, "Python Version %d.%d in %s",
1310 major, minor, pathname);
1311 itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1312 (LPARAM)(LPSTR)vers_name);
1313 SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1314 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1315 (LPARAM)(LPSTR)strdup(pathname));
1316 return TRUE;
1317 }
1318 return FALSE;
1319}
1320#endif /* USE_OTHER_PYTHON_VERSIONS */
1321
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001322typedef struct _InstalledVersionInfo {
1323 char prefix[MAX_PATH+1]; // sys.prefix directory.
1324 HKEY hkey; // Is this Python in HKCU or HKLM?
1325} InstalledVersionInfo;
1326
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001327
1328/*
1329 * Fill the listbox specified by hwnd with all python versions found
1330 * in the registry. version, if not NULL or empty, is the version
1331 * required.
1332 */
1333static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1334{
1335 DWORD index = 0;
1336 char core_version[80];
1337 HKEY hKey;
1338 BOOL result = TRUE;
1339 DWORD bufsize;
1340
1341 if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1342 "Software\\Python\\PythonCore",
1343 0, KEY_READ, &hKey))
1344 return FALSE;
1345 bufsize = sizeof(core_version);
1346 while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1347 core_version, &bufsize, NULL,
1348 NULL, NULL, NULL)) {
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001349 char subkey_name[80], vers_name[80];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001350 int itemindex;
1351 DWORD value_size;
1352 HKEY hk;
1353
1354 bufsize = sizeof(core_version);
1355 ++index;
1356 if (version && *version && strcmp(version, core_version))
1357 continue;
1358
1359 wsprintf(vers_name, "Python Version %s (found in registry)",
1360 core_version);
1361 wsprintf(subkey_name,
1362 "Software\\Python\\PythonCore\\%s\\InstallPath",
1363 core_version);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001364 if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001365 InstalledVersionInfo *ivi =
1366 (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
1367 value_size = sizeof(ivi->prefix);
1368 if (ivi &&
1369 ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
1370 ivi->prefix, &value_size)) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001371 itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001372 (LPARAM)(LPSTR)vers_name);
1373 ivi->hkey = hkRoot;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001374 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001375 (LPARAM)(LPSTR)ivi);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001376 }
1377 RegCloseKey(hk);
1378 }
1379 }
1380 RegCloseKey(hKey);
1381 return result;
1382}
1383
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001384/* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1385BOOL HasLocalMachinePrivs()
1386{
1387 HKEY hKey;
1388 DWORD result;
1389 static char KeyName[] =
1390 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1391
1392 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1393 KeyName,
1394 0,
1395 KEY_CREATE_SUB_KEY,
1396 &hKey);
1397 if (result==0)
1398 RegCloseKey(hKey);
1399 return result==0;
1400}
1401
1402// Check the root registry key to use - either HKLM or HKCU.
1403// If Python is installed in HKCU, then our extension also must be installed
1404// in HKCU - as Python won't be available for other users, we shouldn't either
1405// (and will fail if we are!)
1406// If Python is installed in HKLM, then we will also prefer to use HKLM, but
1407// this may not be possible - so we silently fall back to HKCU.
1408//
1409// We assume hkey_root is already set to where Python itself is installed.
1410void CheckRootKey(HWND hwnd)
1411{
1412 if (hkey_root==HKEY_CURRENT_USER) {
1413 ; // as above, always install ourself in HKCU too.
1414 } else if (hkey_root==HKEY_LOCAL_MACHINE) {
1415 // Python in HKLM, but we may or may not have permissions there.
1416 // Open the uninstall key with 'create' permissions - if this fails,
1417 // we don't have permission.
1418 if (!HasLocalMachinePrivs())
1419 hkey_root = HKEY_CURRENT_USER;
1420 } else {
1421 MessageBox(hwnd, "Don't know Python's installation type",
1422 "Strange", MB_OK | MB_ICONSTOP);
1423 /* Default to wherever they can, but preferring HKLM */
1424 hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1425 }
1426}
1427
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001428/* Return the installation scheme depending on Python version number */
1429SCHEME *GetScheme(int major, int minor)
1430{
1431 if (major > 2)
1432 return new_scheme;
1433 else if((major == 2) && (minor >= 2))
1434 return new_scheme;
1435 return old_scheme;
1436}
1437
1438BOOL CALLBACK
1439SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1440{
1441 LPNMHDR lpnm;
1442
1443 switch (msg) {
1444 case WM_INITDIALOG:
1445 if (hBitmap)
1446 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1447 IMAGE_BITMAP, (LPARAM)hBitmap);
1448 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1449 HKEY_LOCAL_MACHINE, target_version);
1450 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1451 HKEY_CURRENT_USER, target_version);
1452 { /* select the last entry which is the highest python
1453 version found */
1454 int count;
1455 count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1456 LB_GETCOUNT, 0, 0);
1457 if (count && count != LB_ERR)
1458 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1459 count-1, 0);
1460
1461 /* If a specific Python version is required,
1462 * display a prominent notice showing this fact.
1463 */
1464 if (target_version && target_version[0]) {
1465 char buffer[4096];
1466 wsprintf(buffer,
1467 "Python %s is required for this package. "
1468 "Select installation to use:",
1469 target_version);
1470 SetDlgItemText(hwnd, IDC_TITLE, buffer);
1471 }
1472
1473 if (count == 0) {
1474 char Buffer[4096];
1475 char *msg;
1476 if (target_version && target_version[0]) {
1477 wsprintf(Buffer,
1478 "Python version %s required, which was not found"
1479 " in the registry.", target_version);
1480 msg = Buffer;
1481 } else
1482 msg = "No Python installation found in the registry.";
1483 MessageBox(hwnd, msg, "Cannot install",
1484 MB_OK | MB_ICONSTOP);
1485 }
1486 }
1487 goto UpdateInstallDir;
1488 break;
1489
1490 case WM_COMMAND:
1491 switch (LOWORD(wParam)) {
1492/*
1493 case IDC_OTHERPYTHON:
1494 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1495 target_version))
1496 goto UpdateInstallDir;
1497 break;
1498*/
1499 case IDC_VERSIONS_LIST:
1500 switch (HIWORD(wParam)) {
1501 int id;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001502 case LBN_SELCHANGE:
1503 UpdateInstallDir:
1504 PropSheet_SetWizButtons(GetParent(hwnd),
1505 PSWIZB_BACK | PSWIZB_NEXT);
1506 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1507 LB_GETCURSEL, 0, 0);
1508 if (id == LB_ERR) {
1509 PropSheet_SetWizButtons(GetParent(hwnd),
1510 PSWIZB_BACK);
1511 SetDlgItemText(hwnd, IDC_PATH, "");
1512 SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1513 strcpy(python_dir, "");
1514 strcpy(pythondll, "");
1515 } else {
1516 char *pbuf;
1517 int result;
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001518 InstalledVersionInfo *ivi;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001519 PropSheet_SetWizButtons(GetParent(hwnd),
1520 PSWIZB_BACK | PSWIZB_NEXT);
1521 /* Get the python directory */
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001522 ivi = (InstalledVersionInfo *)
1523 SendDlgItemMessage(hwnd,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001524 IDC_VERSIONS_LIST,
1525 LB_GETITEMDATA,
1526 id,
1527 0);
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001528 hkey_root = ivi->hkey;
1529 strcpy(python_dir, ivi->prefix);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001530 SetDlgItemText(hwnd, IDC_PATH, python_dir);
1531 /* retrieve the python version and pythondll to use */
1532 result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1533 LB_GETTEXTLEN, (WPARAM)id, 0);
1534 pbuf = (char *)malloc(result + 1);
1535 if (pbuf) {
1536 /* guess the name of the python-dll */
1537 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1538 LB_GETTEXT, (WPARAM)id,
1539 (LPARAM)pbuf);
1540 result = sscanf(pbuf, "Python Version %d.%d",
1541 &py_major, &py_minor);
Thomas Heller96142192004-04-15 18:19:02 +00001542 if (result == 2) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001543#ifdef _DEBUG
Thomas Hellera19cdad2004-02-20 14:43:21 +00001544 wsprintf(pythondll, "python%d%d_d.dll",
Thomas Heller96142192004-04-15 18:19:02 +00001545 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001546#else
Thomas Heller96142192004-04-15 18:19:02 +00001547 wsprintf(pythondll, "python%d%d.dll",
1548 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001549#endif
Thomas Heller96142192004-04-15 18:19:02 +00001550 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001551 free(pbuf);
1552 } else
1553 strcpy(pythondll, "");
1554 /* retrieve the scheme for this version */
1555 {
1556 char install_path[_MAX_PATH];
1557 SCHEME *scheme = GetScheme(py_major, py_minor);
1558 strcpy(install_path, python_dir);
1559 if (install_path[strlen(install_path)-1] != '\\')
1560 strcat(install_path, "\\");
1561 strcat(install_path, scheme[0].prefix);
1562 SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1563 }
1564 }
1565 }
1566 break;
1567 }
1568 return 0;
1569
1570 case WM_NOTIFY:
1571 lpnm = (LPNMHDR) lParam;
1572
1573 switch (lpnm->code) {
1574 int id;
1575 case PSN_SETACTIVE:
1576 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1577 LB_GETCURSEL, 0, 0);
1578 if (id == LB_ERR)
1579 PropSheet_SetWizButtons(GetParent(hwnd),
1580 PSWIZB_BACK);
1581 else
1582 PropSheet_SetWizButtons(GetParent(hwnd),
1583 PSWIZB_BACK | PSWIZB_NEXT);
1584 break;
1585
1586 case PSN_WIZNEXT:
1587 break;
1588
1589 case PSN_WIZFINISH:
1590 break;
1591
1592 case PSN_RESET:
1593 break;
1594
1595 default:
1596 break;
1597 }
1598 }
1599 return 0;
1600}
1601
1602static BOOL OpenLogfile(char *dir)
1603{
1604 char buffer[_MAX_PATH+1];
1605 time_t ltime;
1606 struct tm *now;
1607 long result;
1608 HKEY hKey, hSubkey;
1609 char subkey_name[256];
1610 static char KeyName[] =
1611 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001612 const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
1613 "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001614 DWORD disposition;
1615
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001616 /* Use Create, as the Uninstall subkey may not exist under HKCU.
1617 Use CreateKeyEx, so we can specify a SAM specifying write access
1618 */
1619 result = RegCreateKeyEx(hkey_root,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001620 KeyName,
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001621 0, /* reserved */
1622 NULL, /* class */
1623 0, /* options */
1624 KEY_CREATE_SUB_KEY, /* sam */
1625 NULL, /* security */
1626 &hKey, /* result key */
1627 NULL); /* disposition */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001628 if (result != ERROR_SUCCESS) {
1629 if (result == ERROR_ACCESS_DENIED) {
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001630 /* This should no longer be able to happen - we have already
1631 checked if they have permissions in HKLM, and all users
1632 should have write access to HKCU.
1633 */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001634 MessageBox(GetFocus(),
1635 "You do not seem to have sufficient access rights\n"
1636 "on this machine to install this software",
1637 NULL,
1638 MB_OK | MB_ICONSTOP);
1639 return FALSE;
1640 } else {
1641 MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1642 }
1643 }
1644
1645 sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1646 logfile = fopen(buffer, "a");
1647 time(&ltime);
1648 now = localtime(&ltime);
1649 strftime(buffer, sizeof(buffer),
1650 "*** Installation started %Y/%m/%d %H:%M ***\n",
1651 localtime(&ltime));
1652 fprintf(logfile, buffer);
1653 fprintf(logfile, "Source: %s\n", modulename);
1654
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001655 /* Root key must be first entry processed by uninstaller. */
1656 fprintf(logfile, "999 Root Key: %s\n", root_name);
1657
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001658 sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
1659
1660 result = RegCreateKeyEx(hKey, subkey_name,
1661 0, NULL, 0,
1662 KEY_WRITE,
1663 NULL,
1664 &hSubkey,
1665 &disposition);
1666
1667 if (result != ERROR_SUCCESS)
1668 MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
1669
1670 RegCloseKey(hKey);
1671
1672 if (disposition == REG_CREATED_NEW_KEY)
1673 fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
1674
1675 sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
1676
1677 result = RegSetValueEx(hSubkey, "DisplayName",
1678 0,
1679 REG_SZ,
1680 buffer,
1681 strlen(buffer)+1);
1682
1683 if (result != ERROR_SUCCESS)
1684 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1685
1686 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1687 KeyName, subkey_name, "DisplayName", buffer);
1688
1689 {
1690 FILE *fp;
1691 sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1692 fp = fopen(buffer, "wb");
1693 fwrite(arc_data, exe_size, 1, fp);
1694 fclose(fp);
1695
1696 sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1697 dir, meta_name, dir, meta_name);
1698
1699 result = RegSetValueEx(hSubkey, "UninstallString",
1700 0,
1701 REG_SZ,
1702 buffer,
1703 strlen(buffer)+1);
1704
1705 if (result != ERROR_SUCCESS)
1706 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1707
1708 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1709 KeyName, subkey_name, "UninstallString", buffer);
1710 }
1711 return TRUE;
1712}
1713
1714static void CloseLogfile(void)
1715{
1716 char buffer[_MAX_PATH+1];
1717 time_t ltime;
1718 struct tm *now;
1719
1720 time(&ltime);
1721 now = localtime(&ltime);
1722 strftime(buffer, sizeof(buffer),
1723 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1724 localtime(&ltime));
1725 fprintf(logfile, buffer);
1726 if (logfile)
1727 fclose(logfile);
1728}
1729
1730BOOL CALLBACK
1731InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1732{
1733 LPNMHDR lpnm;
1734 char Buffer[4096];
1735 SCHEME *scheme;
1736
1737 switch (msg) {
1738 case WM_INITDIALOG:
1739 if (hBitmap)
1740 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1741 IMAGE_BITMAP, (LPARAM)hBitmap);
1742 wsprintf(Buffer,
1743 "Click Next to begin the installation of %s. "
1744 "If you want to review or change any of your "
1745 " installation settings, click Back. "
1746 "Click Cancel to exit the wizard.",
1747 meta_name);
1748 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
Thomas Hellera19cdad2004-02-20 14:43:21 +00001749 SetDlgItemText(hwnd, IDC_INFO, "Ready to install");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001750 break;
1751
1752 case WM_NUMFILES:
1753 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1754 PumpMessages();
1755 return TRUE;
1756
1757 case WM_NEXTFILE:
1758 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1759 0);
1760 SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1761 PumpMessages();
1762 return TRUE;
1763
1764 case WM_NOTIFY:
1765 lpnm = (LPNMHDR) lParam;
1766
1767 switch (lpnm->code) {
1768 case PSN_SETACTIVE:
1769 PropSheet_SetWizButtons(GetParent(hwnd),
1770 PSWIZB_BACK | PSWIZB_NEXT);
1771 break;
1772
1773 case PSN_WIZFINISH:
1774 break;
1775
1776 case PSN_WIZNEXT:
1777 /* Handle a Next button click here */
1778 hDialog = hwnd;
Thomas Hellera19cdad2004-02-20 14:43:21 +00001779 success = TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001780
Thomas Heller32b8f802004-07-02 08:02:40 +00001781 /* Disable the buttons while we work. Sending CANCELTOCLOSE has
1782 the effect of disabling the cancel button, which is a) as we
1783 do everything synchronously we can't cancel, and b) the next
1784 step is 'finished', when it is too late to cancel anyway.
1785 The next step being 'Finished' means we also don't need to
1786 restore the button state back */
1787 PropSheet_SetWizButtons(GetParent(hwnd), 0);
1788 SendMessage(GetParent(hwnd), PSM_CANCELTOCLOSE, 0, 0);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001789 /* Make sure the installation directory name ends in a */
1790 /* backslash */
1791 if (python_dir[strlen(python_dir)-1] != '\\')
1792 strcat(python_dir, "\\");
1793 /* Strip the trailing backslash again */
1794 python_dir[strlen(python_dir)-1] = '\0';
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001795
1796 CheckRootKey(hwnd);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001797
1798 if (!OpenLogfile(python_dir))
1799 break;
1800
1801/*
1802 * The scheme we have to use depends on the Python version...
1803 if sys.version < "2.2":
1804 WINDOWS_SCHEME = {
1805 'purelib': '$base',
1806 'platlib': '$base',
1807 'headers': '$base/Include/$dist_name',
1808 'scripts': '$base/Scripts',
1809 'data' : '$base',
1810 }
1811 else:
1812 WINDOWS_SCHEME = {
1813 'purelib': '$base/Lib/site-packages',
1814 'platlib': '$base/Lib/site-packages',
1815 'headers': '$base/Include/$dist_name',
1816 'scripts': '$base/Scripts',
1817 'data' : '$base',
1818 }
1819*/
1820 scheme = GetScheme(py_major, py_minor);
Thomas Hellera19cdad2004-02-20 14:43:21 +00001821 /* Run the pre-install script. */
1822 if (pre_install_script && *pre_install_script) {
1823 SetDlgItemText (hwnd, IDC_TITLE,
1824 "Running pre-installation script");
1825 run_simple_script(pre_install_script);
1826 }
1827 if (!success) {
1828 break;
1829 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001830 /* Extract all files from the archive */
1831 SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
Thomas Hellera19cdad2004-02-20 14:43:21 +00001832 if (!unzip_archive (scheme,
1833 python_dir, arc_data,
1834 arc_size, notify))
1835 set_failure_reason("Failed to unzip installation files");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001836 /* Compile the py-files */
Thomas Hellera19cdad2004-02-20 14:43:21 +00001837 if (success && pyc_compile) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001838 int errors;
1839 HINSTANCE hPython;
1840 SetDlgItemText(hwnd, IDC_TITLE,
1841 "Compiling files to .pyc...");
1842
1843 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
Thomas Heller48340392004-06-18 17:03:38 +00001844 hPython = LoadPythonDll(pythondll);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001845 if (hPython) {
1846 errors = compile_filelist(hPython, FALSE);
1847 FreeLibrary(hPython);
1848 }
1849 /* Compilation errors are intentionally ignored:
1850 * Python2.0 contains a bug which will result
1851 * in sys.path containing garbage under certain
1852 * circumstances, and an error message will only
1853 * confuse the user.
1854 */
1855 }
Thomas Hellera19cdad2004-02-20 14:43:21 +00001856 if (success && pyo_compile) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001857 int errors;
1858 HINSTANCE hPython;
1859 SetDlgItemText(hwnd, IDC_TITLE,
1860 "Compiling files to .pyo...");
1861
1862 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
Thomas Heller48340392004-06-18 17:03:38 +00001863 hPython = LoadPythonDll(pythondll);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001864 if (hPython) {
1865 errors = compile_filelist(hPython, TRUE);
1866 FreeLibrary(hPython);
1867 }
1868 /* Errors ignored: see above */
1869 }
1870
1871
1872 break;
1873
1874 case PSN_RESET:
1875 break;
1876
1877 default:
1878 break;
1879 }
1880 }
1881 return 0;
1882}
1883
1884
1885BOOL CALLBACK
1886FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1887{
1888 LPNMHDR lpnm;
1889
1890 switch (msg) {
1891 case WM_INITDIALOG:
1892 if (hBitmap)
1893 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1894 IMAGE_BITMAP, (LPARAM)hBitmap);
1895 if (!success)
Thomas Hellera19cdad2004-02-20 14:43:21 +00001896 SetDlgItemText(hwnd, IDC_INFO, get_failure_reason());
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001897
1898 /* async delay: will show the dialog box completely before
1899 the install_script is started */
1900 PostMessage(hwnd, WM_USER, 0, 0L);
1901 return TRUE;
1902
1903 case WM_USER:
1904
Thomas Hellera19cdad2004-02-20 14:43:21 +00001905 if (success && install_script && install_script[0]) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001906 char fname[MAX_PATH];
1907 char *tempname;
1908 FILE *fp;
1909 char buffer[4096];
1910 int n;
1911 HCURSOR hCursor;
1912 HINSTANCE hPython;
1913
1914 char *argv[3] = {NULL, "-install", NULL};
1915
1916 SetDlgItemText(hwnd, IDC_TITLE,
1917 "Please wait while running postinstall script...");
1918 strcpy(fname, python_dir);
1919 strcat(fname, "\\Scripts\\");
1920 strcat(fname, install_script);
1921
1922 if (logfile)
1923 fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
1924
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001925 tempname = tempnam(NULL, NULL);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001926
1927 if (!freopen(tempname, "a", stderr))
1928 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
1929 if (!freopen(tempname, "a", stdout))
1930 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
1931/*
1932 if (0 != setvbuf(stdout, NULL, _IONBF, 0))
1933 MessageBox(GetFocus(), "setvbuf stdout", NULL, MB_OK);
1934*/
1935 hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
1936
1937 argv[0] = fname;
1938
Thomas Heller48340392004-06-18 17:03:38 +00001939 hPython = LoadPythonDll(pythondll);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001940 if (hPython) {
1941 int result;
1942 result = run_installscript(hPython, fname, 2, argv);
1943 if (-1 == result) {
1944 fprintf(stderr, "*** run_installscript: internal error 0x%X ***\n", result);
1945 }
1946 FreeLibrary(hPython);
1947 } else {
1948 fprintf(stderr, "*** Could not load Python ***");
1949 }
1950 fflush(stderr);
1951 fflush(stdout);
1952
1953 fp = fopen(tempname, "rb");
1954 n = fread(buffer, 1, sizeof(buffer), fp);
1955 fclose(fp);
1956 remove(tempname);
1957
1958 buffer[n] = '\0';
1959
1960 SetDlgItemText(hwnd, IDC_INFO, buffer);
1961 SetDlgItemText(hwnd, IDC_TITLE,
1962 "Postinstall script finished.\n"
1963 "Click the Finish button to exit the Setup wizard.");
1964
1965 SetCursor(hCursor);
1966 CloseLogfile();
1967 }
1968
1969 return TRUE;
1970
1971 case WM_NOTIFY:
1972 lpnm = (LPNMHDR) lParam;
1973
1974 switch (lpnm->code) {
1975 case PSN_SETACTIVE: /* Enable the Finish button */
1976 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH);
1977 break;
1978
1979 case PSN_WIZNEXT:
1980 break;
1981
1982 case PSN_WIZFINISH:
1983 break;
1984
1985 case PSN_RESET:
1986 break;
1987
1988 default:
1989 break;
1990 }
1991 }
1992 return 0;
1993}
1994
1995void RunWizard(HWND hwnd)
1996{
1997 PROPSHEETPAGE psp = {0};
1998 HPROPSHEETPAGE ahpsp[4] = {0};
1999 PROPSHEETHEADER psh = {0};
2000
2001 /* Display module information */
2002 psp.dwSize = sizeof(psp);
2003 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2004 psp.hInstance = GetModuleHandle (NULL);
2005 psp.lParam = 0;
2006 psp.pfnDlgProc = IntroDlgProc;
2007 psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO);
2008
2009 ahpsp[0] = CreatePropertySheetPage(&psp);
2010
2011 /* Select python version to use */
2012 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2013 psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTPYTHON);
2014 psp.pfnDlgProc = SelectPythonDlgProc;
2015
2016 ahpsp[1] = CreatePropertySheetPage(&psp);
2017
2018 /* Install the files */
2019 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2020 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFILES);
2021 psp.pfnDlgProc = InstallFilesDlgProc;
2022
2023 ahpsp[2] = CreatePropertySheetPage(&psp);
2024
2025 /* Show success or failure */
2026 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2027 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHED);
2028 psp.pfnDlgProc = FinishedDlgProc;
2029
2030 ahpsp[3] = CreatePropertySheetPage(&psp);
2031
2032 /* Create the property sheet */
2033 psh.dwSize = sizeof(psh);
2034 psh.hInstance = GetModuleHandle(NULL);
2035 psh.hwndParent = hwnd;
2036 psh.phpage = ahpsp;
2037 psh.dwFlags = PSH_WIZARD/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
2038 psh.pszbmWatermark = NULL;
2039 psh.pszbmHeader = NULL;
2040 psh.nStartPage = 0;
2041 psh.nPages = 4;
2042
2043 PropertySheet(&psh);
2044}
2045
2046int DoInstall(void)
2047{
2048 char ini_buffer[4096];
2049
2050 /* Read installation information */
2051 GetPrivateProfileString("Setup", "title", "", ini_buffer,
2052 sizeof(ini_buffer), ini_file);
2053 unescape(title, ini_buffer, sizeof(title));
2054
2055 GetPrivateProfileString("Setup", "info", "", ini_buffer,
2056 sizeof(ini_buffer), ini_file);
2057 unescape(info, ini_buffer, sizeof(info));
2058
2059 GetPrivateProfileString("Setup", "build_info", "", build_info,
2060 sizeof(build_info), ini_file);
2061
2062 pyc_compile = GetPrivateProfileInt("Setup", "target_compile", 1,
2063 ini_file);
2064 pyo_compile = GetPrivateProfileInt("Setup", "target_optimize", 1,
2065 ini_file);
2066
2067 GetPrivateProfileString("Setup", "target_version", "",
2068 target_version, sizeof(target_version),
2069 ini_file);
2070
2071 GetPrivateProfileString("metadata", "name", "",
2072 meta_name, sizeof(meta_name),
2073 ini_file);
2074
2075 GetPrivateProfileString("Setup", "install_script", "",
2076 install_script, sizeof(install_script),
2077 ini_file);
2078
2079
2080 hwndMain = CreateBackground(title);
2081
2082 RunWizard(hwndMain);
2083
2084 /* Clean up */
2085 UnmapViewOfFile(arc_data);
2086 if (ini_file)
2087 DeleteFile(ini_file);
2088
2089 if (hBitmap)
2090 DeleteObject(hBitmap);
2091
2092 return 0;
2093}
2094
2095/*********************** uninstall section ******************************/
2096
2097static int compare(const void *p1, const void *p2)
2098{
2099 return strcmp(*(char **)p2, *(char **)p1);
2100}
2101
2102/*
2103 * Commit suicide (remove the uninstaller itself).
2104 *
2105 * Create a batch file to first remove the uninstaller
2106 * (will succeed after it has finished), then the batch file itself.
2107 *
2108 * This technique has been demonstrated by Jeff Richter,
2109 * MSJ 1/1996
2110 */
2111void remove_exe(void)
2112{
2113 char exename[_MAX_PATH];
2114 char batname[_MAX_PATH];
2115 FILE *fp;
2116 STARTUPINFO si;
2117 PROCESS_INFORMATION pi;
2118
2119 GetModuleFileName(NULL, exename, sizeof(exename));
2120 sprintf(batname, "%s.bat", exename);
2121 fp = fopen(batname, "w");
2122 fprintf(fp, ":Repeat\n");
2123 fprintf(fp, "del \"%s\"\n", exename);
2124 fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
2125 fprintf(fp, "del \"%s\"\n", batname);
2126 fclose(fp);
2127
2128 ZeroMemory(&si, sizeof(si));
2129 si.cb = sizeof(si);
2130 si.dwFlags = STARTF_USESHOWWINDOW;
2131 si.wShowWindow = SW_HIDE;
2132 if (CreateProcess(NULL,
2133 batname,
2134 NULL,
2135 NULL,
2136 FALSE,
2137 CREATE_SUSPENDED | IDLE_PRIORITY_CLASS,
2138 NULL,
2139 "\\",
2140 &si,
2141 &pi)) {
2142 SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE);
2143 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
2144 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
2145 CloseHandle(pi.hProcess);
2146 ResumeThread(pi.hThread);
2147 CloseHandle(pi.hThread);
2148 }
2149}
2150
2151void DeleteRegistryKey(char *string)
2152{
2153 char *keyname;
2154 char *subkeyname;
2155 char *delim;
2156 HKEY hKey;
2157 long result;
2158 char *line;
2159
2160 line = strdup(string); /* so we can change it */
2161
2162 keyname = strchr(line, '[');
2163 if (!keyname)
2164 return;
2165 ++keyname;
2166
2167 subkeyname = strchr(keyname, ']');
2168 if (!subkeyname)
2169 return;
2170 *subkeyname++='\0';
2171 delim = strchr(subkeyname, '\n');
2172 if (delim)
2173 *delim = '\0';
2174
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002175 result = RegOpenKeyEx(hkey_root,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002176 keyname,
2177 0,
2178 KEY_WRITE,
2179 &hKey);
2180
2181 if (result != ERROR_SUCCESS)
2182 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2183 else {
2184 result = RegDeleteKey(hKey, subkeyname);
Thomas Heller55a98642004-07-14 14:53:50 +00002185 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002186 MessageBox(GetFocus(), string, "Could not delete key", MB_OK);
2187 RegCloseKey(hKey);
2188 }
2189 free(line);
2190}
2191
2192void DeleteRegistryValue(char *string)
2193{
2194 char *keyname;
2195 char *valuename;
2196 char *value;
2197 HKEY hKey;
2198 long result;
2199 char *line;
2200
2201 line = strdup(string); /* so we can change it */
2202
2203/* Format is 'Reg DB Value: [key]name=value' */
2204 keyname = strchr(line, '[');
2205 if (!keyname)
2206 return;
2207 ++keyname;
2208 valuename = strchr(keyname, ']');
2209 if (!valuename)
2210 return;
2211 *valuename++ = '\0';
2212 value = strchr(valuename, '=');
2213 if (!value)
2214 return;
2215
2216 *value++ = '\0';
2217
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002218 result = RegOpenKeyEx(hkey_root,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002219 keyname,
2220 0,
2221 KEY_WRITE,
2222 &hKey);
2223 if (result != ERROR_SUCCESS)
2224 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2225 else {
2226 result = RegDeleteValue(hKey, valuename);
Thomas Heller55a98642004-07-14 14:53:50 +00002227 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002228 MessageBox(GetFocus(), string, "Could not delete value", MB_OK);
2229 RegCloseKey(hKey);
2230 }
2231 free(line);
2232}
2233
2234BOOL MyDeleteFile(char *line)
2235{
2236 char *pathname = strchr(line, ':');
2237 if (!pathname)
2238 return FALSE;
2239 ++pathname;
2240 while (isspace(*pathname))
2241 ++pathname;
2242 return DeleteFile(pathname);
2243}
2244
2245BOOL MyRemoveDirectory(char *line)
2246{
2247 char *pathname = strchr(line, ':');
2248 if (!pathname)
2249 return FALSE;
2250 ++pathname;
2251 while (isspace(*pathname))
2252 ++pathname;
2253 return RemoveDirectory(pathname);
2254}
2255
2256BOOL Run_RemoveScript(char *line)
2257{
2258 char *dllname;
2259 char *scriptname;
2260 static char lastscript[MAX_PATH];
2261
2262/* Format is 'Run Scripts: [pythondll]scriptname' */
2263/* XXX Currently, pythondll carries no path!!! */
2264 dllname = strchr(line, '[');
2265 if (!dllname)
2266 return FALSE;
2267 ++dllname;
2268 scriptname = strchr(dllname, ']');
2269 if (!scriptname)
2270 return FALSE;
2271 *scriptname++ = '\0';
2272 /* this function may be called more than one time with the same
2273 script, only run it one time */
2274 if (strcmp(lastscript, scriptname)) {
2275 HINSTANCE hPython;
2276 char *argv[3] = {NULL, "-remove", NULL};
2277 char buffer[4096];
2278 FILE *fp;
2279 char *tempname;
2280 int n;
2281
2282 argv[0] = scriptname;
2283
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002284 tempname = tempnam(NULL, NULL);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002285
2286 if (!freopen(tempname, "a", stderr))
2287 MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
2288 if (!freopen(tempname, "a", stdout))
2289 MessageBox(GetFocus(), "freopen stdout", NULL, MB_OK);
2290
2291 hPython = LoadLibrary(dllname);
2292 if (hPython) {
2293 if (0x80000000 == run_installscript(hPython, scriptname, 2, argv))
2294 fprintf(stderr, "*** Could not load Python ***");
2295 FreeLibrary(hPython);
2296 }
2297
2298 fflush(stderr);
2299 fflush(stdout);
2300
2301 fp = fopen(tempname, "rb");
2302 n = fread(buffer, 1, sizeof(buffer), fp);
2303 fclose(fp);
2304 remove(tempname);
2305
2306 buffer[n] = '\0';
2307 if (buffer[0])
2308 MessageBox(GetFocus(), buffer, "uninstall-script", MB_OK);
2309
2310 strcpy(lastscript, scriptname);
2311 }
2312 return TRUE;
2313}
2314
2315int DoUninstall(int argc, char **argv)
2316{
2317 FILE *logfile;
2318 char buffer[4096];
2319 int nLines = 0;
2320 int i;
2321 char *cp;
2322 int nFiles = 0;
2323 int nDirs = 0;
2324 int nErrors = 0;
2325 char **lines;
2326 int lines_buffer_size = 10;
2327
2328 if (argc != 3) {
2329 MessageBox(NULL,
2330 "Wrong number of args",
2331 NULL,
2332 MB_OK);
2333 return 1; /* Error */
2334 }
2335 if (strcmp(argv[1], "-u")) {
2336 MessageBox(NULL,
2337 "2. arg is not -u",
2338 NULL,
2339 MB_OK);
2340 return 1; /* Error */
2341 }
2342
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002343 logfile = fopen(argv[2], "r");
2344 if (!logfile) {
2345 MessageBox(NULL,
2346 "could not open logfile",
2347 NULL,
2348 MB_OK);
2349 return 1; /* Error */
2350 }
2351
2352 lines = (char **)malloc(sizeof(char *) * lines_buffer_size);
2353 if (!lines)
2354 return SystemError(0, "Out of memory");
2355
2356 /* Read the whole logfile, realloacting the buffer */
2357 while (fgets(buffer, sizeof(buffer), logfile)) {
2358 int len = strlen(buffer);
2359 /* remove trailing white space */
2360 while (isspace(buffer[len-1]))
2361 len -= 1;
2362 buffer[len] = '\0';
2363 lines[nLines++] = strdup(buffer);
2364 if (nLines >= lines_buffer_size) {
2365 lines_buffer_size += 10;
2366 lines = (char **)realloc(lines,
2367 sizeof(char *) * lines_buffer_size);
2368 if (!lines)
2369 return SystemError(0, "Out of memory");
2370 }
2371 }
2372 fclose(logfile);
2373
2374 /* Sort all the lines, so that highest 3-digit codes are first */
2375 qsort(&lines[0], nLines, sizeof(char *),
2376 compare);
2377
2378 if (IDYES != MessageBox(NULL,
2379 "Are you sure you want to remove\n"
2380 "this package from your computer?",
2381 "Please confirm",
2382 MB_YESNO | MB_ICONQUESTION))
2383 return 0;
2384
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002385 hkey_root = HKEY_LOCAL_MACHINE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002386 cp = "";
2387 for (i = 0; i < nLines; ++i) {
2388 /* Ignore duplicate lines */
2389 if (strcmp(cp, lines[i])) {
2390 int ign;
2391 cp = lines[i];
2392 /* Parse the lines */
Mark Hammondf9bfdd82004-07-02 23:53:16 +00002393 if (2 == sscanf(cp, "%d Root Key: %s", &ign, &buffer)) {
2394 if (strcmp(buffer, "HKEY_CURRENT_USER")==0)
2395 hkey_root = HKEY_CURRENT_USER;
2396 else {
2397 // HKLM - check they have permissions.
2398 if (!HasLocalMachinePrivs()) {
2399 MessageBox(GetFocus(),
2400 "You do not seem to have sufficient access rights\n"
2401 "on this machine to uninstall this software",
2402 NULL,
2403 MB_OK | MB_ICONSTOP);
2404 return 1; /* Error */
2405 }
2406 }
2407 } else if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002408 if (MyRemoveDirectory(cp))
2409 ++nDirs;
2410 else {
2411 int code = GetLastError();
2412 if (code != 2 && code != 3) { /* file or path not found */
2413 ++nErrors;
2414 }
2415 }
2416 } else if (2 == sscanf(cp, "%d File Copy: %s", &ign, &buffer)) {
2417 if (MyDeleteFile(cp))
2418 ++nFiles;
2419 else {
2420 int code = GetLastError();
2421 if (code != 2 && code != 3) { /* file or path not found */
2422 ++nErrors;
2423 }
2424 }
2425 } else if (2 == sscanf(cp, "%d File Overwrite: %s", &ign, &buffer)) {
2426 if (MyDeleteFile(cp))
2427 ++nFiles;
2428 else {
2429 int code = GetLastError();
2430 if (code != 2 && code != 3) { /* file or path not found */
2431 ++nErrors;
2432 }
2433 }
2434 } else if (2 == sscanf(cp, "%d Reg DB Key: %s", &ign, &buffer)) {
2435 DeleteRegistryKey(cp);
2436 } else if (2 == sscanf(cp, "%d Reg DB Value: %s", &ign, &buffer)) {
2437 DeleteRegistryValue(cp);
2438 } else if (2 == sscanf(cp, "%d Run Script: %s", &ign, &buffer)) {
2439 Run_RemoveScript(cp);
2440 }
2441 }
2442 }
2443
2444 if (DeleteFile(argv[2])) {
2445 ++nFiles;
2446 } else {
2447 ++nErrors;
2448 SystemError(GetLastError(), argv[2]);
2449 }
2450 if (nErrors)
2451 wsprintf(buffer,
2452 "%d files and %d directories removed\n"
2453 "%d files or directories could not be removed",
2454 nFiles, nDirs, nErrors);
2455 else
2456 wsprintf(buffer, "%d files and %d directories removed",
2457 nFiles, nDirs);
2458 MessageBox(NULL, buffer, "Uninstall Finished!",
2459 MB_OK | MB_ICONINFORMATION);
2460 remove_exe();
2461 return 0;
2462}
2463
2464int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
2465 LPSTR lpszCmdLine, INT nCmdShow)
2466{
2467 extern int __argc;
2468 extern char **__argv;
2469 char *basename;
2470
2471 GetModuleFileName(NULL, modulename, sizeof(modulename));
2472
2473 /* Map the executable file to memory */
2474 arc_data = MapExistingFile(modulename, &arc_size);
2475 if (!arc_data) {
2476 SystemError(GetLastError(), "Could not open archive");
2477 return 1;
2478 }
2479
2480 /* OK. So this program can act as installer (self-extracting
2481 * zip-file, or as uninstaller when started with '-u logfile'
2482 * command line flags.
2483 *
2484 * The installer is usually started without command line flags,
2485 * and the uninstaller is usually started with the '-u logfile'
2486 * flag. What to do if some innocent user double-clicks the
2487 * exe-file?
2488 * The following implements a defensive strategy...
2489 */
2490
2491 /* Try to extract the configuration data into a temporary file */
Thomas Hellera19cdad2004-02-20 14:43:21 +00002492 if (ExtractInstallData(arc_data, arc_size, &exe_size,
2493 &ini_file, &pre_install_script))
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002494 return DoInstall();
2495
2496 if (!ini_file && __argc > 1) {
2497 return DoUninstall(__argc, __argv);
2498 }
2499
2500
2501 basename = strrchr(modulename, '\\');
2502 if (basename)
2503 ++basename;
2504
2505 /* Last guess about the purpose of this program */
2506 if (basename && (0 == strncmp(basename, "Remove", 6)))
2507 SystemError(0, "This program is normally started by windows");
2508 else
2509 SystemError(0, "Setup program invalid or damaged");
2510 return 1;
2511}