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