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