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