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