blob: 6d01ad5c2d50e7dde1d19e372823a92f42b75ae8 [file] [log] [blame]
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001/*
Steve Dower65e4cb12014-11-22 12:54:57 -08002 IMPORTANT NOTE: IF THIS FILE IS CHANGED, PCBUILD\BDIST_WININST.VCXPROJ MUST
3 BE REBUILT AS WELL.
Thomas Hellerd1d92ea2004-07-14 15:17:04 +00004
Steve Dower65e4cb12014-11-22 12:54:57 -08005 IF CHANGES TO THIS FILE ARE CHECKED IN, THE RECOMPILED BINARIES MUST BE
6 CHECKED IN AS WELL!
Thomas Hellerd1d92ea2004-07-14 15:17:04 +00007*/
8
9/*
Thomas Hellerbb4b7d22002-11-22 20:39:33 +000010 * 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:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000022 * [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
Thomas Hellerbb4b7d22002-11-22 20:39:33 +000030 *
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000031 * [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
Thomas Hellerbb4b7d22002-11-22 20:39:33 +000037 *
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
Ezio Melotti42da6632011-03-15 05:18:48 +020064 * additionally to those found in the registry,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +000065 * 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>
Thomas Heller9f2e3be2005-02-03 20:35:10 +000090#include <sys/types.h>
91#include <sys/stat.h>
92#include <malloc.h>
93#include <io.h>
94#include <fcntl.h>
Thomas Hellerbb4b7d22002-11-22 20:39:33 +000095
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 */
113FILE *logfile;
114
115char modulename[MAX_PATH];
Mark Hammond891f2632009-01-29 13:08:01 +0000116wchar_t wmodulename[MAX_PATH];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000117
118HWND hwndMain;
119HWND hDialog;
120
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000121char *ini_file; /* Full pathname of ini-file */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000122/* From ini-file */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000123char info[4096]; /* [Setup] info= */
124char title[80]; /* [Setup] title=, contains package name
125 including version: "Distutils-1.0.1" */
126char target_version[10]; /* [Setup] target_version=, required python
127 version or empty string */
128char build_info[80]; /* [Setup] build_info=, distutils version
129 and build date */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000130
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000131char meta_name[80]; /* package name without version like
132 'Distutils' */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000133char install_script[MAX_PATH];
Thomas Hellera19cdad2004-02-20 14:43:21 +0000134char *pre_install_script; /* run before we install a single file */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000135
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000136char user_access_control[10]; // one of 'auto', 'force', otherwise none.
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000137
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000138int py_major, py_minor; /* Python version selected for installation */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000139
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000140char *arc_data; /* memory mapped archive */
141DWORD arc_size; /* number of bytes in archive */
142int exe_size; /* number of bytes for exe-file portion */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000143char python_dir[MAX_PATH];
144char pythondll[MAX_PATH];
145BOOL pyc_compile, pyo_compile;
Mark Hammondf9bfdd82004-07-02 23:53:16 +0000146/* Either HKLM or HKCU, depending on where Python itself is registered, and
147 the permissions of the current user. */
148HKEY hkey_root = (HKEY)-1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000149
Ezio Melotti13925002011-03-16 11:05:33 +0200150BOOL success; /* Installation successful? */
Thomas Hellera19cdad2004-02-20 14:43:21 +0000151char *failure_reason = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000152
153HANDLE hBitmap;
154char *bitmap_bytes;
155
Steve Dower332334f2016-01-16 13:54:53 -0800156static const char *REGISTRY_SUFFIX_6432 =
Steve Dower43478812016-12-13 09:06:24 -0800157#ifdef _WIN64
Steve Dower332334f2016-01-16 13:54:53 -0800158 "";
159#else
160 "-32";
161#endif
162
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000163
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
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000170static 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! */
174SCHEME old_scheme[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000175 { "PURELIB", "" },
176 { "PLATLIB", "" },
177 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
178 { "SCRIPTS", "Scripts\\" },
179 { "DATA", "" },
180 { NULL, NULL },
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000181};
182
183SCHEME new_scheme[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000184 { "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 },
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000190};
191
192static void unescape(char *dst, char *src, unsigned size)
193{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000194 char *eon;
195 char ch;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000196
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000197 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';
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000227}
228
229static struct tagFile {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000230 char *path;
231 struct tagFile *next;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000232} *file_list = NULL;
233
Thomas Hellera19cdad2004-02-20 14:43:21 +0000234static void set_failure_reason(char *reason)
235{
236 if (failure_reason)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000237 free(failure_reason);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000238 failure_reason = strdup(reason);
239 success = FALSE;
240}
241static char *get_failure_reason()
242{
243 if (!failure_reason)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000244 return "Installation failed.";
Thomas Hellera19cdad2004-02-20 14:43:21 +0000245 return failure_reason;
246}
247
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000248static void add_to_filelist(char *path)
249{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000250 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;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000255}
256
257static int do_compile_files(int (__cdecl * PyRun_SimpleString)(char *),
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000258 int optimize)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000259{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000260 struct tagFile *p;
261 int total, n;
262 char Buffer[MAX_PATH + 64];
263 int errors = 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000264
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000265 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);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000274
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000275 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);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000291
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000292 SendDlgItemMessage(hDialog, IDC_PROGRESS, PBM_SETPOS, n, 0);
293 SetDlgItemText(hDialog, IDC_INFO, p->path);
294 p = p->next;
295 }
296 return errors;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000297}
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
307typedef void PyObject;
308
Mark Hammond891f2632009-01-29 13:08:01 +0000309// Convert a "char *" string to "whcar_t *", or NULL on error.
310// Result string must be free'd
311wchar_t *widen_string(char *src)
312{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000313 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;
Mark Hammond891f2632009-01-29 13:08:01 +0000329}
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000330
331/*
332 * Returns number of files which failed to compile,
333 * -1 if python could not be loaded at all
334 */
335static int compile_filelist(HINSTANCE hPython, BOOL optimize_flag)
336{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000337 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);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000343
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000344 int errors = 0;
345 struct tagFile *p = file_list;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000346
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000347 if (!p)
348 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000349
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000350 if (!Py_Initialize || !Py_SetProgramName || !Py_Finalize)
351 return -1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000352
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000353 if (!PyRun_SimpleString || !PySys_GetObject || !Py_OptimizeFlag)
354 return -1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000355
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000356 *Py_OptimizeFlag = optimize_flag ? 1 : 0;
357 Py_SetProgramName(wmodulename);
358 Py_Initialize();
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000359
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000360 errors += do_compile_files(PyRun_SimpleString, optimize_flag);
361 Py_Finalize();
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000362
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000363 return errors;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000364}
365
366typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
367
368struct PyMethodDef {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000369 char *ml_name;
370 PyCFunction ml_meth;
371 int ml_flags;
372 char *ml_doc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000373};
374typedef struct PyMethodDef PyMethodDef;
375
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000376// XXX - all of these are potentially fragile! We load and unload
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000377// the Python DLL multiple times - so storing functions pointers
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000378// 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.
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000382void *(*g_Py_BuildValue)(char *, ...);
383int (*g_PyArg_ParseTuple)(PyObject *, char *, ...);
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000384PyObject * (*g_PyLong_FromVoidPtr)(void *);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000385
386PyObject *g_PyExc_ValueError;
387PyObject *g_PyExc_OSError;
388
389PyObject *(*g_PyErr_Format)(PyObject *, char *, ...);
390
391#define DEF_CSIDL(name) { name, #name }
392
393struct {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000394 int nFolder;
395 char *name;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000396} csidl_names[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000397 /* Startup menu for all users.
398 NT only */
399 DEF_CSIDL(CSIDL_COMMON_STARTMENU),
400 /* Startup menu. */
401 DEF_CSIDL(CSIDL_STARTMENU),
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000402
403/* DEF_CSIDL(CSIDL_COMMON_APPDATA), */
404/* DEF_CSIDL(CSIDL_LOCAL_APPDATA), */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000405 /* Repository for application-specific data.
406 Needs Internet Explorer 4.0 */
407 DEF_CSIDL(CSIDL_APPDATA),
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000408
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000409 /* The desktop for all users.
410 NT only */
411 DEF_CSIDL(CSIDL_COMMON_DESKTOPDIRECTORY),
412 /* The desktop. */
413 DEF_CSIDL(CSIDL_DESKTOPDIRECTORY),
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000414
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000415 /* Startup folder for all users.
416 NT only */
417 DEF_CSIDL(CSIDL_COMMON_STARTUP),
418 /* Startup folder. */
419 DEF_CSIDL(CSIDL_STARTUP),
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000420
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000421 /* 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),
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000426
427/* DEF_CSIDL(CSIDL_PROGRAM_FILES_COMMON), */
428/* DEF_CSIDL(CSIDL_PROGRAM_FILES), */
429
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000430 /* Virtual folder containing fonts. */
431 DEF_CSIDL(CSIDL_FONTS),
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000432};
433
434#define DIM(a) (sizeof(a) / sizeof((a)[0]))
435
436static PyObject *FileCreated(PyObject *self, PyObject *args)
437{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000438 char *path;
439 if (!g_PyArg_ParseTuple(args, "s", &path))
440 return NULL;
441 notify(FILE_CREATED, path);
442 return g_Py_BuildValue("");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000443}
444
445static PyObject *DirectoryCreated(PyObject *self, PyObject *args)
446{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000447 char *path;
448 if (!g_PyArg_ParseTuple(args, "s", &path))
449 return NULL;
450 notify(DIR_CREATED, path);
451 return g_Py_BuildValue("");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000452}
453
454static PyObject *GetSpecialFolderPath(PyObject *self, PyObject *args)
455{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000456 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);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000463
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000464 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000476
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000477 if (!g_PyArg_ParseTuple(args, "s", &name))
478 return NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000479
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000480 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;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000502}
503
504static PyObject *CreateShortcut(PyObject *self, PyObject *args)
505{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000506 char *path; /* path and filename */
507 char *description;
508 char *filename;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000509
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000510 char *arguments = NULL;
511 char *iconpath = NULL;
512 int iconindex = 0;
513 char *workdir = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000514
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000515 WCHAR wszFilename[MAX_PATH];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000516
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000517 IShellLink *ps1 = NULL;
518 IPersistFile *pPf = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000519
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000520 HRESULT hr;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000521
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000522 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000528
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000529 if (!g_PyArg_ParseTuple(args, "sss|sssi",
530 &path, &description, &filename,
531 &arguments, &workdir, &iconpath, &iconindex))
532 return NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000533
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000534 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000544
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000545 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000552
553
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000554 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000560
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000561 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000567
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000568 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000576
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000577 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000585
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000586 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 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000594
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000595 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
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000611 error:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000612 if (pPf)
613 pPf->lpVtbl->Release(pPf);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000614
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000615 if (ps1)
616 ps1->lpVtbl->Release(ps1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000617
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000618 CoUninitialize();
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000619
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000620 return NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000621}
622
Thomas Hellera19cdad2004-02-20 14:43:21 +0000623static PyObject *PyMessageBox(PyObject *self, PyObject *args)
624{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000625 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);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000632}
633
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530634static PyObject *GetRootHKey(PyObject *self, PyObject *Py_UNUSED(ignored))
Mark Hammondf9bfdd82004-07-02 23:53:16 +0000635{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000636 return g_PyLong_FromVoidPtr(hkey_root);
Mark Hammondf9bfdd82004-07-02 23:53:16 +0000637}
638
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000639#define METH_VARARGS 0x0001
Mark Hammondf9bfdd82004-07-02 23:53:16 +0000640#define METH_NOARGS 0x0004
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000641
642PyMethodDef meth[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000643 {"create_shortcut", CreateShortcut, METH_VARARGS, NULL},
644 {"get_special_folder_path", GetSpecialFolderPath, METH_VARARGS, NULL},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530645 {"get_root_hkey", GetRootHKey, METH_NOARGS, NULL},
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000646 {"file_created", FileCreated, METH_VARARGS, NULL},
647 {"directory_created", DirectoryCreated, METH_VARARGS, NULL},
648 {"message_box", PyMessageBox, METH_VARARGS, NULL},
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000649};
650
Thomas Heller48340392004-06-18 17:03:38 +0000651static HINSTANCE LoadPythonDll(char *fname)
652{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000653 char fullpath[_MAX_PATH];
654 LONG size = sizeof(fullpath);
655 char subkey_name[80];
656 char buffer[260 + 12];
657 HINSTANCE h;
Thomas Heller8abe7bf2005-02-03 20:11:28 +0000658
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000659 /* make sure PYTHONHOME is set, to that sys.path is initialized correctly */
660 wsprintf(buffer, "PYTHONHOME=%s", python_dir);
661 _putenv(buffer);
662 h = LoadLibrary(fname);
663 if (h)
664 return h;
665 wsprintf(subkey_name,
Steve Dower332334f2016-01-16 13:54:53 -0800666 "SOFTWARE\\Python\\PythonCore\\%d.%d%s\\InstallPath",
667 py_major, py_minor, REGISTRY_SUFFIX_6432);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000668 if (ERROR_SUCCESS != RegQueryValue(HKEY_CURRENT_USER, subkey_name,
669 fullpath, &size) &&
670 ERROR_SUCCESS != RegQueryValue(HKEY_LOCAL_MACHINE, subkey_name,
671 fullpath, &size))
672 return NULL;
673 strcat(fullpath, "\\");
674 strcat(fullpath, fname);
Steve Dower332334f2016-01-16 13:54:53 -0800675 // We use LOAD_WITH_ALTERED_SEARCH_PATH to ensure any dependent DLLs
676 // next to the Python DLL (eg, the CRT DLL) are also loaded.
677 return LoadLibraryEx(fullpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
Thomas Heller48340392004-06-18 17:03:38 +0000678}
679
Thomas Hellera19cdad2004-02-20 14:43:21 +0000680static int prepare_script_environment(HINSTANCE hPython)
681{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000682 PyObject *mod;
683 DECLPROC(hPython, PyObject *, PyImport_ImportModule, (char *));
684 DECLPROC(hPython, int, PyObject_SetAttrString, (PyObject *, char *, PyObject *));
685 DECLPROC(hPython, PyObject *, PyObject_GetAttrString, (PyObject *, char *));
686 DECLPROC(hPython, PyObject *, PyCFunction_New, (PyMethodDef *, PyObject *));
687 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
688 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
689 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
690 DECLPROC(hPython, PyObject *, PyLong_FromVoidPtr, (void *));
691 if (!PyImport_ImportModule || !PyObject_GetAttrString ||
692 !PyObject_SetAttrString || !PyCFunction_New)
693 return 1;
694 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
695 return 1;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000696
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000697 mod = PyImport_ImportModule("builtins");
698 if (mod) {
699 int i;
700 g_PyExc_ValueError = PyObject_GetAttrString(mod, "ValueError");
701 g_PyExc_OSError = PyObject_GetAttrString(mod, "OSError");
702 for (i = 0; i < DIM(meth); ++i) {
703 PyObject_SetAttrString(mod, meth[i].ml_name,
704 PyCFunction_New(&meth[i], NULL));
705 }
706 }
707 g_Py_BuildValue = Py_BuildValue;
708 g_PyArg_ParseTuple = PyArg_ParseTuple;
709 g_PyErr_Format = PyErr_Format;
710 g_PyLong_FromVoidPtr = PyLong_FromVoidPtr;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000711
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000712 return 0;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000713}
714
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000715/*
716 * This function returns one of the following error codes:
717 * 1 if the Python-dll does not export the functions we need
718 * 2 if no install-script is specified in pathname
719 * 3 if the install-script file could not be opened
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000720 * the return value of PyRun_SimpleString() or Py_FinalizeEx() otherwise,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000721 * which is 0 if everything is ok, -1 if an exception had occurred
722 * in the install-script.
723 */
724
725static int
Mark Hammond6d0e9752009-01-29 12:36:50 +0000726do_run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000727{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000728 int fh, result, i;
729 static wchar_t *wargv[256];
730 DECLPROC(hPython, void, Py_Initialize, (void));
731 DECLPROC(hPython, int, PySys_SetArgv, (int, wchar_t **));
732 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000733 DECLPROC(hPython, int, Py_FinalizeEx, (void));
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000734 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
735 DECLPROC(hPython, PyObject *, PyCFunction_New,
736 (PyMethodDef *, PyObject *));
737 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
738 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000739
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000740 if (!Py_Initialize || !PySys_SetArgv
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000741 || !PyRun_SimpleString || !Py_FinalizeEx)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000742 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000743
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000744 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
745 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000746
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000747 if (!PyCFunction_New || !PyArg_ParseTuple || !PyErr_Format)
748 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000749
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000750 if (pathname == NULL || pathname[0] == '\0')
751 return 2;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000752
Victor Stinnerdaf45552013-08-28 00:53:59 +0200753 fh = open(pathname, _O_RDONLY | O_NOINHERIT);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000754 if (-1 == fh) {
755 fprintf(stderr, "Could not open postinstall-script %s\n",
756 pathname);
757 return 3;
758 }
Mark Hammond6d0e9752009-01-29 12:36:50 +0000759
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000760 SetDlgItemText(hDialog, IDC_INFO, "Running Script...");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000761
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000762 Py_Initialize();
Mark Hammond891f2632009-01-29 13:08:01 +0000763
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000764 prepare_script_environment(hPython);
765 // widen the argv array for py3k.
766 memset(wargv, 0, sizeof(wargv));
767 for (i=0;i<argc;i++)
768 wargv[i] = argv[i] ? widen_string(argv[i]) : NULL;
769 PySys_SetArgv(argc, wargv);
770 // free the strings we just widened.
771 for (i=0;i<argc;i++)
772 if (wargv[i])
773 free(wargv[i]);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000774
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000775 result = 3;
776 {
777 struct _stat statbuf;
778 if(0 == _fstat(fh, &statbuf)) {
779 char *script = alloca(statbuf.st_size + 5);
780 int n = read(fh, script, statbuf.st_size);
781 if (n > 0) {
782 script[n] = '\n';
783 script[n+1] = 0;
784 result = PyRun_SimpleString(script);
785 }
786 }
787 }
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000788 if (Py_FinalizeEx() < 0) {
789 result = -1;
790 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000791
792 close(fh);
793 return result;
Mark Hammond6d0e9752009-01-29 12:36:50 +0000794}
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000795
Mark Hammond6d0e9752009-01-29 12:36:50 +0000796static int
797run_installscript(char *pathname, int argc, char **argv, char **pOutput)
798{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000799 HINSTANCE hPython;
800 int result = 1;
801 int out_buf_size;
802 HANDLE redirected, old_stderr, old_stdout;
803 char *tempname;
Mark Hammond6d0e9752009-01-29 12:36:50 +0000804
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000805 *pOutput = NULL;
Mark Hammond6d0e9752009-01-29 12:36:50 +0000806
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000807 tempname = tempnam(NULL, NULL);
808 // We use a static CRT while the Python version we load uses
Ezio Melotti13925002011-03-16 11:05:33 +0200809 // the CRT from one of various possible DLLs. As a result we
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000810 // need to redirect the standard handles using the API rather
811 // than the CRT.
812 redirected = CreateFile(
813 tempname,
814 GENERIC_WRITE | GENERIC_READ,
815 FILE_SHARE_READ,
816 NULL,
817 CREATE_ALWAYS,
818 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
819 NULL);
820 old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
821 old_stderr = GetStdHandle(STD_ERROR_HANDLE);
822 SetStdHandle(STD_OUTPUT_HANDLE, redirected);
823 SetStdHandle(STD_ERROR_HANDLE, redirected);
Mark Hammond6d0e9752009-01-29 12:36:50 +0000824
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000825 hPython = LoadPythonDll(pythondll);
826 if (hPython) {
827 result = do_run_installscript(hPython, pathname, argc, argv);
828 FreeLibrary(hPython);
829 } else {
830 fprintf(stderr, "*** Could not load Python ***");
831 }
832 SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
833 SetStdHandle(STD_ERROR_HANDLE, old_stderr);
834 out_buf_size = min(GetFileSize(redirected, NULL), 4096);
835 *pOutput = malloc(out_buf_size+1);
836 if (*pOutput) {
837 DWORD nread = 0;
838 SetFilePointer(redirected, 0, 0, FILE_BEGIN);
839 ReadFile(redirected, *pOutput, out_buf_size, &nread, NULL);
840 (*pOutput)[nread] = '\0';
841 }
842 CloseHandle(redirected);
843 DeleteFile(tempname);
844 return result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000845}
846
Thomas Hellera19cdad2004-02-20 14:43:21 +0000847static int do_run_simple_script(HINSTANCE hPython, char *script)
848{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000849 int rc;
850 DECLPROC(hPython, void, Py_Initialize, (void));
851 DECLPROC(hPython, void, Py_SetProgramName, (wchar_t *));
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000852 DECLPROC(hPython, int, Py_FinalizeEx, (void));
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000853 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
854 DECLPROC(hPython, void, PyErr_Print, (void));
Thomas Hellera19cdad2004-02-20 14:43:21 +0000855
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000856 if (!Py_Initialize || !Py_SetProgramName || !Py_FinalizeEx ||
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000857 !PyRun_SimpleString || !PyErr_Print)
858 return -1;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000859
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000860 Py_SetProgramName(wmodulename);
861 Py_Initialize();
862 prepare_script_environment(hPython);
863 rc = PyRun_SimpleString(script);
864 if (rc)
865 PyErr_Print();
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000866 if (Py_FinalizeEx() < 0) {
867 rc = -1;
868 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000869 return rc;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000870}
871
872static int run_simple_script(char *script)
873{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000874 int rc;
875 HINSTANCE hPython;
876 char *tempname = tempnam(NULL, NULL);
877 // Redirect output using win32 API - see comments above...
878 HANDLE redirected = CreateFile(
879 tempname,
880 GENERIC_WRITE | GENERIC_READ,
881 FILE_SHARE_READ,
882 NULL,
883 CREATE_ALWAYS,
884 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
885 NULL);
886 HANDLE old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
887 HANDLE old_stderr = GetStdHandle(STD_ERROR_HANDLE);
888 SetStdHandle(STD_OUTPUT_HANDLE, redirected);
889 SetStdHandle(STD_ERROR_HANDLE, redirected);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000890
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000891 hPython = LoadPythonDll(pythondll);
892 if (!hPython) {
893 char reason[128];
894 wsprintf(reason, "Can't load Python for pre-install script (%d)", GetLastError());
895 set_failure_reason(reason);
896 return -1;
897 }
898 rc = do_run_simple_script(hPython, script);
899 FreeLibrary(hPython);
900 SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
901 SetStdHandle(STD_ERROR_HANDLE, old_stderr);
902 /* We only care about the output when we fail. If the script works
903 OK, then we discard it
904 */
905 if (rc) {
906 int err_buf_size;
907 char *err_buf;
908 const char *prefix = "Running the pre-installation script failed\r\n";
909 int prefix_len = strlen(prefix);
910 err_buf_size = GetFileSize(redirected, NULL);
911 if (err_buf_size==INVALID_FILE_SIZE) // an error - let's try anyway...
912 err_buf_size = 4096;
913 err_buf = malloc(prefix_len + err_buf_size + 1);
914 if (err_buf) {
915 DWORD n = 0;
916 strcpy(err_buf, prefix);
917 SetFilePointer(redirected, 0, 0, FILE_BEGIN);
918 ReadFile(redirected, err_buf+prefix_len, err_buf_size, &n, NULL);
919 err_buf[prefix_len+n] = '\0';
920 set_failure_reason(err_buf);
921 free(err_buf);
922 } else {
923 set_failure_reason("Out of memory!");
924 }
925 }
926 CloseHandle(redirected);
927 DeleteFile(tempname);
928 return rc;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000929}
930
931
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000932static BOOL SystemError(int error, char *msg)
933{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000934 char Buffer[1024];
935 int n;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000936
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000937 if (error) {
938 LPVOID lpMsgBuf;
939 FormatMessage(
940 FORMAT_MESSAGE_ALLOCATE_BUFFER |
941 FORMAT_MESSAGE_FROM_SYSTEM,
942 NULL,
943 error,
944 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
945 (LPSTR)&lpMsgBuf,
946 0,
947 NULL
948 );
949 strncpy(Buffer, lpMsgBuf, sizeof(Buffer));
950 LocalFree(lpMsgBuf);
951 } else
952 Buffer[0] = '\0';
953 n = lstrlen(Buffer);
954 _snprintf(Buffer+n, sizeof(Buffer)-n, msg);
955 MessageBox(hwndMain, Buffer, "Runtime Error", MB_OK | MB_ICONSTOP);
956 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000957}
958
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000959static BOOL notify (int code, char *fmt, ...)
960{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000961 char Buffer[1024];
962 va_list marker;
963 BOOL result = TRUE;
964 int a, b;
965 char *cp;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000966
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000967 va_start(marker, fmt);
968 _vsnprintf(Buffer, sizeof(Buffer), fmt, marker);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000969
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000970 switch (code) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000971/* Questions */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000972 case CAN_OVERWRITE:
973 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000974
975/* Information notification */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000976 case DIR_CREATED:
977 if (logfile)
978 fprintf(logfile, "100 Made Dir: %s\n", fmt);
979 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000980
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000981 case FILE_CREATED:
982 if (logfile)
983 fprintf(logfile, "200 File Copy: %s\n", fmt);
984 goto add_to_filelist_label;
985 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000986
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000987 case FILE_OVERWRITTEN:
988 if (logfile)
989 fprintf(logfile, "200 File Overwrite: %s\n", fmt);
990 add_to_filelist_label:
991 if ((cp = strrchr(fmt, '.')) && (0 == strcmp (cp, ".py")))
992 add_to_filelist(fmt);
993 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000994
995/* Error Messages */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000996 case ZLIB_ERROR:
997 MessageBox(GetFocus(), Buffer, "Error",
998 MB_OK | MB_ICONWARNING);
999 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001000
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001001 case SYSTEM_ERROR:
1002 SystemError(GetLastError(), Buffer);
1003 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001004
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001005 case NUM_FILES:
1006 a = va_arg(marker, int);
1007 b = va_arg(marker, int);
1008 SendMessage(hDialog, WM_NUMFILES, 0, MAKELPARAM(0, a));
1009 SendMessage(hDialog, WM_NEXTFILE, b,(LPARAM)fmt);
1010 }
1011 va_end(marker);
1012
1013 return result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001014}
1015
1016static char *MapExistingFile(char *pathname, DWORD *psize)
1017{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001018 HANDLE hFile, hFileMapping;
1019 DWORD nSizeLow, nSizeHigh;
1020 char *data;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001021
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001022 hFile = CreateFile(pathname,
1023 GENERIC_READ, FILE_SHARE_READ, NULL,
1024 OPEN_EXISTING,
1025 FILE_ATTRIBUTE_NORMAL, NULL);
1026 if (hFile == INVALID_HANDLE_VALUE)
1027 return NULL;
1028 nSizeLow = GetFileSize(hFile, &nSizeHigh);
1029 hFileMapping = CreateFileMapping(hFile,
1030 NULL, PAGE_READONLY, 0, 0, NULL);
1031 CloseHandle(hFile);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001032
Gregory P. Smithb803c6c2013-03-23 16:05:36 -07001033 if (hFileMapping == NULL)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001034 return NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001035
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001036 data = MapViewOfFile(hFileMapping,
1037 FILE_MAP_READ, 0, 0, 0);
1038
1039 CloseHandle(hFileMapping);
1040 *psize = nSizeLow;
1041 return data;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001042}
1043
1044
1045static void create_bitmap(HWND hwnd)
1046{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001047 BITMAPFILEHEADER *bfh;
1048 BITMAPINFO *bi;
1049 HDC hdc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001050
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001051 if (!bitmap_bytes)
1052 return;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001053
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001054 if (hBitmap)
1055 return;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001056
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001057 hdc = GetDC(hwnd);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001058
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001059 bfh = (BITMAPFILEHEADER *)bitmap_bytes;
1060 bi = (BITMAPINFO *)(bitmap_bytes + sizeof(BITMAPFILEHEADER));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001061
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001062 hBitmap = CreateDIBitmap(hdc,
1063 &bi->bmiHeader,
1064 CBM_INIT,
1065 bitmap_bytes + bfh->bfOffBits,
1066 bi,
1067 DIB_RGB_COLORS);
1068 ReleaseDC(hwnd, hdc);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001069}
1070
Thomas Hellera19cdad2004-02-20 14:43:21 +00001071/* Extract everything we need to begin the installation. Currently this
1072 is the INI filename with install data, and the raw pre-install script
1073*/
1074static BOOL ExtractInstallData(char *data, DWORD size, int *pexe_size,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001075 char **out_ini_file, char **out_preinstall_script)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001076{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001077 /* read the end of central directory record */
1078 struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
1079 (struct eof_cdir)];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001080
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001081 int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
1082 pe->ofsCDir;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001083
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001084 int ofs = arc_start - sizeof (struct meta_data_hdr);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001085
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001086 /* read meta_data info */
1087 struct meta_data_hdr *pmd = (struct meta_data_hdr *)&data[ofs];
1088 char *src, *dst;
1089 char *ini_file;
1090 char tempdir[MAX_PATH];
Thomas Hellera19cdad2004-02-20 14:43:21 +00001091
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001092 /* ensure that if we fail, we don't have garbage out pointers */
1093 *out_ini_file = *out_preinstall_script = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001094
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001095 if (pe->tag != 0x06054b50) {
1096 return FALSE;
1097 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001098
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001099 if (pmd->tag != 0x1234567B) {
1100 return SystemError(0,
1101 "Invalid cfgdata magic number (see bdist_wininst.py)");
1102 }
1103 if (ofs < 0) {
1104 return FALSE;
1105 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001106
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001107 if (pmd->bitmap_size) {
1108 /* Store pointer to bitmap bytes */
1109 bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
1110 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001111
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001112 *pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
1113
1114 src = ((char *)pmd) - pmd->uncomp_size;
1115 ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
1116 if (!ini_file)
1117 return FALSE;
1118 if (!GetTempPath(sizeof(tempdir), tempdir)
1119 || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
1120 SystemError(GetLastError(),
1121 "Could not create temporary file");
1122 return FALSE;
1123 }
1124
1125 dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
1126 0, 0, NULL/*notify*/);
1127 if (!dst)
1128 return FALSE;
1129 /* Up to the first \0 is the INI file data. */
1130 strncpy(dst, src, pmd->uncomp_size);
1131 src += strlen(dst) + 1;
1132 /* Up to next \0 is the pre-install script */
1133 *out_preinstall_script = strdup(src);
1134 *out_ini_file = ini_file;
1135 UnmapViewOfFile(dst);
1136 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001137}
1138
1139static void PumpMessages(void)
1140{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001141 MSG msg;
1142 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1143 TranslateMessage(&msg);
1144 DispatchMessage(&msg);
1145 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001146}
1147
1148LRESULT CALLBACK
1149WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1150{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001151 HDC hdc;
1152 HFONT hFont;
1153 int h;
1154 PAINTSTRUCT ps;
1155 switch (msg) {
1156 case WM_PAINT:
1157 hdc = BeginPaint(hwnd, &ps);
1158 h = GetSystemMetrics(SM_CYSCREEN) / 10;
1159 hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
1160 0, 0, 0, 0, 0, 0, 0, "Times Roman");
1161 hFont = SelectObject(hdc, hFont);
1162 SetBkMode(hdc, TRANSPARENT);
1163 TextOut(hdc, 15, 15, title, strlen(title));
1164 SetTextColor(hdc, RGB(255, 255, 255));
1165 TextOut(hdc, 10, 10, title, strlen(title));
1166 DeleteObject(SelectObject(hdc, hFont));
1167 EndPaint(hwnd, &ps);
1168 return 0;
1169 }
1170 return DefWindowProc(hwnd, msg, wParam, lParam);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001171}
1172
1173static HWND CreateBackground(char *title)
1174{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001175 WNDCLASS wc;
1176 HWND hwnd;
1177 char buffer[4096];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001178
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001179 wc.style = CS_VREDRAW | CS_HREDRAW;
1180 wc.lpfnWndProc = WindowProc;
1181 wc.cbWndExtra = 0;
1182 wc.cbClsExtra = 0;
1183 wc.hInstance = GetModuleHandle(NULL);
1184 wc.hIcon = NULL;
1185 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1186 wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
1187 wc.lpszMenuName = NULL;
1188 wc.lpszClassName = "SetupWindowClass";
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001189
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001190 if (!RegisterClass(&wc))
1191 MessageBox(hwndMain,
1192 "Could not register window class",
1193 "Setup.exe", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001194
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001195 wsprintf(buffer, "Setup %s", title);
1196 hwnd = CreateWindow("SetupWindowClass",
1197 buffer,
1198 0,
1199 0, 0,
1200 GetSystemMetrics(SM_CXFULLSCREEN),
1201 GetSystemMetrics(SM_CYFULLSCREEN),
1202 NULL,
1203 NULL,
1204 GetModuleHandle(NULL),
1205 NULL);
1206 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
1207 UpdateWindow(hwnd);
1208 return hwnd;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001209}
1210
1211/*
1212 * Center a window on the screen
1213 */
1214static void CenterWindow(HWND hwnd)
1215{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001216 RECT rc;
1217 int w, h;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001218
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001219 GetWindowRect(hwnd, &rc);
1220 w = GetSystemMetrics(SM_CXSCREEN);
1221 h = GetSystemMetrics(SM_CYSCREEN);
1222 MoveWindow(hwnd,
1223 (w - (rc.right-rc.left))/2,
1224 (h - (rc.bottom-rc.top))/2,
1225 rc.right-rc.left, rc.bottom-rc.top, FALSE);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001226}
1227
1228#include <prsht.h>
1229
Steve Dower65e4cb12014-11-22 12:54:57 -08001230INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001231IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1232{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001233 LPNMHDR lpnm;
1234 char Buffer[4096];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001235
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001236 switch (msg) {
1237 case WM_INITDIALOG:
1238 create_bitmap(hwnd);
1239 if(hBitmap)
1240 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1241 IMAGE_BITMAP, (LPARAM)hBitmap);
1242 CenterWindow(GetParent(hwnd));
1243 wsprintf(Buffer,
1244 "This Wizard will install %s on your computer. "
1245 "Click Next to continue "
1246 "or Cancel to exit the Setup Wizard.",
1247 meta_name);
1248 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1249 SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
1250 SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
1251 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001252
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001253 case WM_NOTIFY:
1254 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001255
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001256 switch (lpnm->code) {
1257 case PSN_SETACTIVE:
1258 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
1259 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001260
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001261 case PSN_WIZNEXT:
1262 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001263
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001264 case PSN_RESET:
1265 break;
1266
1267 default:
1268 break;
1269 }
1270 }
1271 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001272}
1273
1274#ifdef USE_OTHER_PYTHON_VERSIONS
1275/* These are really private variables used to communicate
1276 * between StatusRoutine and CheckPythonExe
1277 */
1278char bound_image_dll[_MAX_PATH];
1279int bound_image_major;
1280int bound_image_minor;
1281
1282static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001283 PSTR ImageName,
1284 PSTR DllName,
1285 ULONG Va,
1286 ULONG Parameter)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001287{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001288 char fname[_MAX_PATH];
1289 int int_version;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001290
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001291 switch(reason) {
1292 case BindOutOfMemory:
1293 case BindRvaToVaFailed:
1294 case BindNoRoomInImage:
1295 case BindImportProcedureFailed:
1296 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001297
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001298 case BindImportProcedure:
1299 case BindForwarder:
1300 case BindForwarderNOT:
1301 case BindImageModified:
1302 case BindExpandFileHeaders:
1303 case BindImageComplete:
1304 case BindSymbolsNotUpdated:
1305 case BindMismatchedSymbols:
1306 case BindImportModuleFailed:
1307 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001308
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001309 case BindImportModule:
1310 if (1 == sscanf(DllName, "python%d", &int_version)) {
1311 SearchPath(NULL, DllName, NULL, sizeof(fname),
1312 fname, NULL);
1313 strcpy(bound_image_dll, fname);
1314 bound_image_major = int_version / 10;
1315 bound_image_minor = int_version % 10;
1316 OutputDebugString("BOUND ");
1317 OutputDebugString(fname);
1318 OutputDebugString("\n");
1319 }
1320 break;
1321 }
1322 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001323}
1324
1325/*
1326 */
1327static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1328{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001329 void (__cdecl * Py_Initialize)(void);
1330 void (__cdecl * Py_SetProgramName)(char *);
1331 void (__cdecl * Py_Finalize)(void);
1332 void* (__cdecl * PySys_GetObject)(char *);
1333 void (__cdecl * PySys_SetArgv)(int, char **);
1334 char* (__cdecl * Py_GetPrefix)(void);
1335 char* (__cdecl * Py_GetPath)(void);
1336 HINSTANCE hPython;
1337 LPSTR prefix = NULL;
1338 int (__cdecl * PyRun_SimpleString)(char *);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001339
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001340 {
1341 char Buffer[256];
1342 wsprintf(Buffer, "PYTHONHOME=%s", exe);
1343 *strrchr(Buffer, '\\') = '\0';
1344// MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1345 _putenv(Buffer);
1346 _putenv("PYTHONPATH=");
1347 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001348
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001349 hPython = LoadLibrary(dll);
1350 if (!hPython)
1351 return NULL;
1352 Py_Initialize = (void (*)(void))GetProcAddress
1353 (hPython,"Py_Initialize");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001354
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001355 PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1356 (hPython,"PySys_SetArgv");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001357
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001358 PyRun_SimpleString = (int (*)(char *))GetProcAddress
1359 (hPython,"PyRun_SimpleString");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001360
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001361 Py_SetProgramName = (void (*)(char *))GetProcAddress
1362 (hPython,"Py_SetProgramName");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001363
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001364 PySys_GetObject = (void* (*)(char *))GetProcAddress
1365 (hPython,"PySys_GetObject");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001366
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001367 Py_GetPrefix = (char * (*)(void))GetProcAddress
1368 (hPython,"Py_GetPrefix");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001369
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001370 Py_GetPath = (char * (*)(void))GetProcAddress
1371 (hPython,"Py_GetPath");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001372
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001373 Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1374 "Py_Finalize");
1375 Py_SetProgramName(exe);
1376 Py_Initialize();
1377 PySys_SetArgv(1, &exe);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001378
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001379 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1380 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001381
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001382 Py_Finalize();
1383 FreeLibrary(hPython);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001384
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001385 return prefix;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001386}
1387
1388static BOOL
1389CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1390{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001391 bound_image_dll[0] = '\0';
1392 if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1393 pathname,
1394 NULL,
1395 NULL,
1396 StatusRoutine))
1397 return SystemError(0, "Could not bind image");
1398 if (bound_image_dll[0] == '\0')
1399 return SystemError(0, "Does not seem to be a python executable");
1400 *pmajor = bound_image_major;
1401 *pminor = bound_image_minor;
1402 if (version && *version) {
1403 char core_version[12];
1404 wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1405 if (strcmp(version, core_version))
1406 return SystemError(0, "Wrong Python version");
1407 }
1408 get_sys_prefix(pathname, bound_image_dll);
1409 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001410}
1411
1412/*
1413 * Browse for other python versions. Insert it into the listbox specified
1414 * by hwnd. version, if not NULL or empty, is the version required.
1415 */
1416static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1417{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001418 char vers_name[_MAX_PATH + 80];
1419 DWORD itemindex;
1420 OPENFILENAME of;
1421 char pathname[_MAX_PATH];
1422 DWORD result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001423
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001424 strcpy(pathname, "python.exe");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001425
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001426 memset(&of, 0, sizeof(of));
1427 of.lStructSize = sizeof(OPENFILENAME);
1428 of.hwndOwner = GetParent(hwnd);
1429 of.hInstance = NULL;
1430 of.lpstrFilter = "python.exe\0python.exe\0";
1431 of.lpstrCustomFilter = NULL;
1432 of.nMaxCustFilter = 0;
1433 of.nFilterIndex = 1;
1434 of.lpstrFile = pathname;
1435 of.nMaxFile = sizeof(pathname);
1436 of.lpstrFileTitle = NULL;
1437 of.nMaxFileTitle = 0;
1438 of.lpstrInitialDir = NULL;
1439 of.lpstrTitle = "Python executable";
1440 of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1441 of.lpstrDefExt = "exe";
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001442
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001443 result = GetOpenFileName(&of);
1444 if (result) {
1445 int major, minor;
1446 if (!CheckPythonExe(pathname, version, &major, &minor)) {
1447 return FALSE;
1448 }
1449 *strrchr(pathname, '\\') = '\0';
1450 wsprintf(vers_name, "Python Version %d.%d in %s",
1451 major, minor, pathname);
1452 itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1453 (LPARAM)(LPSTR)vers_name);
1454 SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1455 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1456 (LPARAM)(LPSTR)strdup(pathname));
1457 return TRUE;
1458 }
1459 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001460}
1461#endif /* USE_OTHER_PYTHON_VERSIONS */
1462
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001463typedef struct _InstalledVersionInfo {
1464 char prefix[MAX_PATH+1]; // sys.prefix directory.
1465 HKEY hkey; // Is this Python in HKCU or HKLM?
1466} InstalledVersionInfo;
1467
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001468
1469/*
1470 * Fill the listbox specified by hwnd with all python versions found
1471 * in the registry. version, if not NULL or empty, is the version
1472 * required.
1473 */
1474static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1475{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001476 DWORD index = 0;
1477 char core_version[80];
1478 HKEY hKey;
1479 BOOL result = TRUE;
1480 DWORD bufsize;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001481
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001482 if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1483 "Software\\Python\\PythonCore",
1484 0, KEY_READ, &hKey))
1485 return FALSE;
1486 bufsize = sizeof(core_version);
1487 while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1488 core_version, &bufsize, NULL,
1489 NULL, NULL, NULL)) {
1490 char subkey_name[80], vers_name[80];
1491 int itemindex;
1492 DWORD value_size;
1493 HKEY hk;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001494
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001495 bufsize = sizeof(core_version);
1496 ++index;
1497 if (version && *version && strcmp(version, core_version))
1498 continue;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001499
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001500 wsprintf(vers_name, "Python Version %s (found in registry)",
1501 core_version);
1502 wsprintf(subkey_name,
1503 "Software\\Python\\PythonCore\\%s\\InstallPath",
1504 core_version);
1505 if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
1506 InstalledVersionInfo *ivi =
1507 (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
1508 value_size = sizeof(ivi->prefix);
1509 if (ivi &&
1510 ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
1511 ivi->prefix, &value_size)) {
1512 itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
1513 (LPARAM)(LPSTR)vers_name);
1514 ivi->hkey = hkRoot;
1515 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1516 (LPARAM)(LPSTR)ivi);
1517 }
1518 RegCloseKey(hk);
1519 }
1520 }
1521 RegCloseKey(hKey);
1522 return result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001523}
1524
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001525/* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1526BOOL HasLocalMachinePrivs()
1527{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001528 HKEY hKey;
1529 DWORD result;
1530 static char KeyName[] =
1531 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001532
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001533 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1534 KeyName,
1535 0,
1536 KEY_CREATE_SUB_KEY,
1537 &hKey);
1538 if (result==0)
1539 RegCloseKey(hKey);
1540 return result==0;
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001541}
1542
1543// Check the root registry key to use - either HKLM or HKCU.
1544// If Python is installed in HKCU, then our extension also must be installed
1545// in HKCU - as Python won't be available for other users, we shouldn't either
1546// (and will fail if we are!)
1547// If Python is installed in HKLM, then we will also prefer to use HKLM, but
1548// this may not be possible - so we silently fall back to HKCU.
1549//
1550// We assume hkey_root is already set to where Python itself is installed.
1551void CheckRootKey(HWND hwnd)
1552{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001553 if (hkey_root==HKEY_CURRENT_USER) {
1554 ; // as above, always install ourself in HKCU too.
1555 } else if (hkey_root==HKEY_LOCAL_MACHINE) {
1556 // Python in HKLM, but we may or may not have permissions there.
1557 // Open the uninstall key with 'create' permissions - if this fails,
1558 // we don't have permission.
1559 if (!HasLocalMachinePrivs())
1560 hkey_root = HKEY_CURRENT_USER;
1561 } else {
1562 MessageBox(hwnd, "Don't know Python's installation type",
1563 "Strange", MB_OK | MB_ICONSTOP);
1564 /* Default to wherever they can, but preferring HKLM */
1565 hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1566 }
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001567}
1568
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001569/* Return the installation scheme depending on Python version number */
1570SCHEME *GetScheme(int major, int minor)
1571{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001572 if (major > 2)
1573 return new_scheme;
1574 else if((major == 2) && (minor >= 2))
1575 return new_scheme;
1576 return old_scheme;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001577}
1578
Steve Dower65e4cb12014-11-22 12:54:57 -08001579INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001580SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1581{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001582 LPNMHDR lpnm;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001583
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001584 switch (msg) {
1585 case WM_INITDIALOG:
1586 if (hBitmap)
1587 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1588 IMAGE_BITMAP, (LPARAM)hBitmap);
1589 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1590 HKEY_LOCAL_MACHINE, target_version);
1591 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1592 HKEY_CURRENT_USER, target_version);
1593 { /* select the last entry which is the highest python
1594 version found */
1595 int count;
1596 count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1597 LB_GETCOUNT, 0, 0);
1598 if (count && count != LB_ERR)
1599 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1600 count-1, 0);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001601
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001602 /* If a specific Python version is required,
1603 * display a prominent notice showing this fact.
1604 */
1605 if (target_version && target_version[0]) {
1606 char buffer[4096];
1607 wsprintf(buffer,
1608 "Python %s is required for this package. "
1609 "Select installation to use:",
1610 target_version);
1611 SetDlgItemText(hwnd, IDC_TITLE, buffer);
1612 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001613
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001614 if (count == 0) {
1615 char Buffer[4096];
Serhiy Storchakae2f92de2017-11-11 13:06:26 +02001616 const char *msg;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001617 if (target_version && target_version[0]) {
1618 wsprintf(Buffer,
1619 "Python version %s required, which was not found"
1620 " in the registry.", target_version);
1621 msg = Buffer;
1622 } else
1623 msg = "No Python installation found in the registry.";
1624 MessageBox(hwnd, msg, "Cannot install",
1625 MB_OK | MB_ICONSTOP);
1626 }
1627 }
1628 goto UpdateInstallDir;
1629 break;
1630
1631 case WM_COMMAND:
1632 switch (LOWORD(wParam)) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001633/*
1634 case IDC_OTHERPYTHON:
1635 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1636 target_version))
1637 goto UpdateInstallDir;
1638 break;
1639*/
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001640 case IDC_VERSIONS_LIST:
1641 switch (HIWORD(wParam)) {
1642 int id;
1643 case LBN_SELCHANGE:
1644 UpdateInstallDir:
1645 PropSheet_SetWizButtons(GetParent(hwnd),
1646 PSWIZB_BACK | PSWIZB_NEXT);
1647 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1648 LB_GETCURSEL, 0, 0);
1649 if (id == LB_ERR) {
1650 PropSheet_SetWizButtons(GetParent(hwnd),
1651 PSWIZB_BACK);
1652 SetDlgItemText(hwnd, IDC_PATH, "");
1653 SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1654 strcpy(python_dir, "");
1655 strcpy(pythondll, "");
1656 } else {
1657 char *pbuf;
1658 int result;
1659 InstalledVersionInfo *ivi;
1660 PropSheet_SetWizButtons(GetParent(hwnd),
1661 PSWIZB_BACK | PSWIZB_NEXT);
1662 /* Get the python directory */
Martin Panter6d57fe12016-09-17 03:26:16 +00001663 ivi = (InstalledVersionInfo *)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001664 SendDlgItemMessage(hwnd,
Martin Panter6d57fe12016-09-17 03:26:16 +00001665 IDC_VERSIONS_LIST,
1666 LB_GETITEMDATA,
1667 id,
1668 0);
1669 hkey_root = ivi->hkey;
1670 strcpy(python_dir, ivi->prefix);
1671 SetDlgItemText(hwnd, IDC_PATH, python_dir);
1672 /* retrieve the python version and pythondll to use */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001673 result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1674 LB_GETTEXTLEN, (WPARAM)id, 0);
1675 pbuf = (char *)malloc(result + 1);
1676 if (pbuf) {
1677 /* guess the name of the python-dll */
1678 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1679 LB_GETTEXT, (WPARAM)id,
1680 (LPARAM)pbuf);
1681 result = sscanf(pbuf, "Python Version %d.%d",
1682 &py_major, &py_minor);
1683 if (result == 2) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001684#ifdef _DEBUG
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001685 wsprintf(pythondll, "python%d%d_d.dll",
1686 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001687#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001688 wsprintf(pythondll, "python%d%d.dll",
1689 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001690#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001691 }
1692 free(pbuf);
1693 } else
1694 strcpy(pythondll, "");
1695 /* retrieve the scheme for this version */
1696 {
1697 char install_path[_MAX_PATH];
1698 SCHEME *scheme = GetScheme(py_major, py_minor);
1699 strcpy(install_path, python_dir);
1700 if (install_path[strlen(install_path)-1] != '\\')
1701 strcat(install_path, "\\");
1702 strcat(install_path, scheme[0].prefix);
1703 SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1704 }
1705 }
1706 }
1707 break;
1708 }
1709 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001710
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001711 case WM_NOTIFY:
1712 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001713
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001714 switch (lpnm->code) {
1715 int id;
1716 case PSN_SETACTIVE:
1717 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1718 LB_GETCURSEL, 0, 0);
1719 if (id == LB_ERR)
1720 PropSheet_SetWizButtons(GetParent(hwnd),
1721 PSWIZB_BACK);
1722 else
1723 PropSheet_SetWizButtons(GetParent(hwnd),
1724 PSWIZB_BACK | PSWIZB_NEXT);
1725 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001726
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001727 case PSN_WIZNEXT:
1728 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001729
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001730 case PSN_WIZFINISH:
1731 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001732
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001733 case PSN_RESET:
1734 break;
1735
1736 default:
1737 break;
1738 }
1739 }
1740 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001741}
1742
1743static BOOL OpenLogfile(char *dir)
1744{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001745 char buffer[_MAX_PATH+1];
1746 time_t ltime;
1747 struct tm *now;
1748 long result;
1749 HKEY hKey, hSubkey;
1750 char subkey_name[256];
1751 static char KeyName[] =
1752 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1753 const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
1754 "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
1755 DWORD disposition;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001756
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001757 /* Use Create, as the Uninstall subkey may not exist under HKCU.
1758 Use CreateKeyEx, so we can specify a SAM specifying write access
1759 */
1760 result = RegCreateKeyEx(hkey_root,
1761 KeyName,
1762 0, /* reserved */
1763 NULL, /* class */
1764 0, /* options */
1765 KEY_CREATE_SUB_KEY, /* sam */
1766 NULL, /* security */
1767 &hKey, /* result key */
1768 NULL); /* disposition */
1769 if (result != ERROR_SUCCESS) {
1770 if (result == ERROR_ACCESS_DENIED) {
1771 /* This should no longer be able to happen - we have already
1772 checked if they have permissions in HKLM, and all users
1773 should have write access to HKCU.
1774 */
1775 MessageBox(GetFocus(),
1776 "You do not seem to have sufficient access rights\n"
1777 "on this machine to install this software",
1778 NULL,
1779 MB_OK | MB_ICONSTOP);
1780 return FALSE;
1781 } else {
1782 MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1783 }
1784 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001785
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001786 sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1787 logfile = fopen(buffer, "a");
Benjamin Peterson25c7d3f2014-11-27 20:39:02 -06001788 if (!logfile) {
1789 char error[1024];
1790
1791 sprintf(error, "Can't create \"%s\" (%s).\n\n"
1792 "Try to execute the installer as administrator.",
1793 buffer, strerror(errno));
1794 MessageBox(GetFocus(), error, NULL, MB_OK | MB_ICONSTOP);
1795 return FALSE;
1796 }
1797
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001798 time(&ltime);
1799 now = localtime(&ltime);
1800 strftime(buffer, sizeof(buffer),
1801 "*** Installation started %Y/%m/%d %H:%M ***\n",
1802 localtime(&ltime));
1803 fprintf(logfile, buffer);
1804 fprintf(logfile, "Source: %s\n", modulename);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001805
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001806 /* Root key must be first entry processed by uninstaller. */
1807 fprintf(logfile, "999 Root Key: %s\n", root_name);
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001808
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001809 sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001810
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001811 result = RegCreateKeyEx(hKey, subkey_name,
1812 0, NULL, 0,
1813 KEY_WRITE,
1814 NULL,
1815 &hSubkey,
1816 &disposition);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001817
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001818 if (result != ERROR_SUCCESS)
1819 MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001820
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001821 RegCloseKey(hKey);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001822
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001823 if (disposition == REG_CREATED_NEW_KEY)
1824 fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001825
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001826 sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001827
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001828 result = RegSetValueEx(hSubkey, "DisplayName",
1829 0,
1830 REG_SZ,
1831 buffer,
1832 strlen(buffer)+1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001833
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001834 if (result != ERROR_SUCCESS)
1835 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001836
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001837 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1838 KeyName, subkey_name, "DisplayName", buffer);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001839
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001840 {
1841 FILE *fp;
1842 sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1843 fp = fopen(buffer, "wb");
1844 fwrite(arc_data, exe_size, 1, fp);
1845 fclose(fp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001846
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001847 sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1848 dir, meta_name, dir, meta_name);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001849
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001850 result = RegSetValueEx(hSubkey, "UninstallString",
1851 0,
1852 REG_SZ,
1853 buffer,
1854 strlen(buffer)+1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001855
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001856 if (result != ERROR_SUCCESS)
1857 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1858
1859 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1860 KeyName, subkey_name, "UninstallString", buffer);
1861 }
1862 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001863}
1864
1865static void CloseLogfile(void)
1866{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001867 char buffer[_MAX_PATH+1];
1868 time_t ltime;
1869 struct tm *now;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001870
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001871 time(&ltime);
1872 now = localtime(&ltime);
1873 strftime(buffer, sizeof(buffer),
1874 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1875 localtime(&ltime));
1876 fprintf(logfile, buffer);
1877 if (logfile)
1878 fclose(logfile);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001879}
1880
Steve Dower65e4cb12014-11-22 12:54:57 -08001881INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001882InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1883{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001884 LPNMHDR lpnm;
1885 char Buffer[4096];
1886 SCHEME *scheme;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001887
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001888 switch (msg) {
1889 case WM_INITDIALOG:
1890 if (hBitmap)
1891 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1892 IMAGE_BITMAP, (LPARAM)hBitmap);
1893 wsprintf(Buffer,
1894 "Click Next to begin the installation of %s. "
1895 "If you want to review or change any of your "
1896 " installation settings, click Back. "
1897 "Click Cancel to exit the wizard.",
1898 meta_name);
1899 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1900 SetDlgItemText(hwnd, IDC_INFO, "Ready to install");
1901 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001902
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001903 case WM_NUMFILES:
1904 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1905 PumpMessages();
1906 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001907
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001908 case WM_NEXTFILE:
1909 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1910 0);
1911 SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1912 PumpMessages();
1913 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001914
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001915 case WM_NOTIFY:
1916 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001917
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001918 switch (lpnm->code) {
1919 case PSN_SETACTIVE:
1920 PropSheet_SetWizButtons(GetParent(hwnd),
1921 PSWIZB_BACK | PSWIZB_NEXT);
1922 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001923
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001924 case PSN_WIZFINISH:
1925 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001926
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001927 case PSN_WIZNEXT:
1928 /* Handle a Next button click here */
1929 hDialog = hwnd;
1930 success = TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001931
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001932 /* Disable the buttons while we work. Sending CANCELTOCLOSE has
1933 the effect of disabling the cancel button, which is a) as we
1934 do everything synchronously we can't cancel, and b) the next
1935 step is 'finished', when it is too late to cancel anyway.
1936 The next step being 'Finished' means we also don't need to
1937 restore the button state back */
1938 PropSheet_SetWizButtons(GetParent(hwnd), 0);
1939 SendMessage(GetParent(hwnd), PSM_CANCELTOCLOSE, 0, 0);
1940 /* Make sure the installation directory name ends in a */
1941 /* backslash */
1942 if (python_dir[strlen(python_dir)-1] != '\\')
1943 strcat(python_dir, "\\");
1944 /* Strip the trailing backslash again */
1945 python_dir[strlen(python_dir)-1] = '\0';
1946
1947 CheckRootKey(hwnd);
1948
1949 if (!OpenLogfile(python_dir))
1950 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001951
1952/*
1953 * The scheme we have to use depends on the Python version...
1954 if sys.version < "2.2":
Serhiy Storchakad741a882015-06-11 00:06:39 +03001955 WINDOWS_SCHEME = {
1956 'purelib': '$base',
1957 'platlib': '$base',
1958 'headers': '$base/Include/$dist_name',
1959 'scripts': '$base/Scripts',
1960 'data' : '$base',
1961 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001962 else:
Serhiy Storchakad741a882015-06-11 00:06:39 +03001963 WINDOWS_SCHEME = {
1964 'purelib': '$base/Lib/site-packages',
1965 'platlib': '$base/Lib/site-packages',
1966 'headers': '$base/Include/$dist_name',
1967 'scripts': '$base/Scripts',
1968 'data' : '$base',
1969 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001970*/
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001971 scheme = GetScheme(py_major, py_minor);
1972 /* Run the pre-install script. */
1973 if (pre_install_script && *pre_install_script) {
1974 SetDlgItemText (hwnd, IDC_TITLE,
1975 "Running pre-installation script");
1976 run_simple_script(pre_install_script);
1977 }
1978 if (!success) {
1979 break;
1980 }
1981 /* Extract all files from the archive */
1982 SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
1983 if (!unzip_archive (scheme,
1984 python_dir, arc_data,
1985 arc_size, notify))
1986 set_failure_reason("Failed to unzip installation files");
1987 /* Compile the py-files */
1988 if (success && pyc_compile) {
1989 int errors;
1990 HINSTANCE hPython;
1991 SetDlgItemText(hwnd, IDC_TITLE,
1992 "Compiling files to .pyc...");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001993
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001994 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
1995 hPython = LoadPythonDll(pythondll);
1996 if (hPython) {
1997 errors = compile_filelist(hPython, FALSE);
1998 FreeLibrary(hPython);
1999 }
2000 /* Compilation errors are intentionally ignored:
2001 * Python2.0 contains a bug which will result
2002 * in sys.path containing garbage under certain
2003 * circumstances, and an error message will only
2004 * confuse the user.
2005 */
2006 }
2007 if (success && pyo_compile) {
2008 int errors;
2009 HINSTANCE hPython;
2010 SetDlgItemText(hwnd, IDC_TITLE,
2011 "Compiling files to .pyo...");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002012
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002013 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
2014 hPython = LoadPythonDll(pythondll);
2015 if (hPython) {
2016 errors = compile_filelist(hPython, TRUE);
2017 FreeLibrary(hPython);
2018 }
2019 /* Errors ignored: see above */
2020 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002021
2022
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002023 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002024
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002025 case PSN_RESET:
2026 break;
2027
2028 default:
2029 break;
2030 }
2031 }
2032 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002033}
2034
2035
Steve Dower65e4cb12014-11-22 12:54:57 -08002036INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002037FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2038{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002039 LPNMHDR lpnm;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002040
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002041 switch (msg) {
2042 case WM_INITDIALOG:
2043 if (hBitmap)
2044 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
2045 IMAGE_BITMAP, (LPARAM)hBitmap);
2046 if (!success)
2047 SetDlgItemText(hwnd, IDC_INFO, get_failure_reason());
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002048
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002049 /* async delay: will show the dialog box completely before
2050 the install_script is started */
2051 PostMessage(hwnd, WM_USER, 0, 0L);
2052 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002053
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002054 case WM_USER:
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002055
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002056 if (success && install_script && install_script[0]) {
2057 char fname[MAX_PATH];
2058 char *buffer;
2059 HCURSOR hCursor;
2060 int result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002061
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002062 char *argv[3] = {NULL, "-install", NULL};
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002063
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002064 SetDlgItemText(hwnd, IDC_TITLE,
2065 "Please wait while running postinstall script...");
2066 strcpy(fname, python_dir);
2067 strcat(fname, "\\Scripts\\");
2068 strcat(fname, install_script);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002069
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002070 if (logfile)
2071 fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002072
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002073 hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002074
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002075 argv[0] = fname;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002076
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002077 result = run_installscript(fname, 2, argv, &buffer);
2078 if (0 != result) {
2079 fprintf(stderr, "*** run_installscript: internal error 0x%X ***\n", result);
2080 }
2081 if (buffer)
2082 SetDlgItemText(hwnd, IDC_INFO, buffer);
2083 SetDlgItemText(hwnd, IDC_TITLE,
2084 "Postinstall script finished.\n"
2085 "Click the Finish button to exit the Setup wizard.");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002086
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002087 free(buffer);
2088 SetCursor(hCursor);
2089 CloseLogfile();
2090 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002091
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002092 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002093
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002094 case WM_NOTIFY:
2095 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002096
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002097 switch (lpnm->code) {
2098 case PSN_SETACTIVE: /* Enable the Finish button */
2099 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH);
2100 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002101
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002102 case PSN_WIZNEXT:
2103 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002104
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002105 case PSN_WIZFINISH:
2106 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002107
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002108 case PSN_RESET:
2109 break;
2110
2111 default:
2112 break;
2113 }
2114 }
2115 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002116}
2117
2118void RunWizard(HWND hwnd)
2119{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002120 PROPSHEETPAGE psp = {0};
2121 HPROPSHEETPAGE ahpsp[4] = {0};
2122 PROPSHEETHEADER psh = {0};
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002123
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002124 /* Display module information */
2125 psp.dwSize = sizeof(psp);
2126 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2127 psp.hInstance = GetModuleHandle (NULL);
2128 psp.lParam = 0;
2129 psp.pfnDlgProc = IntroDlgProc;
2130 psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002131
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002132 ahpsp[0] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002133
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002134 /* Select python version to use */
2135 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2136 psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTPYTHON);
2137 psp.pfnDlgProc = SelectPythonDlgProc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002138
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002139 ahpsp[1] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002140
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002141 /* Install the files */
2142 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2143 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFILES);
2144 psp.pfnDlgProc = InstallFilesDlgProc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002145
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002146 ahpsp[2] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002147
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002148 /* Show success or failure */
2149 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2150 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHED);
2151 psp.pfnDlgProc = FinishedDlgProc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002152
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002153 ahpsp[3] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002154
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002155 /* Create the property sheet */
2156 psh.dwSize = sizeof(psh);
2157 psh.hInstance = GetModuleHandle(NULL);
2158 psh.hwndParent = hwnd;
2159 psh.phpage = ahpsp;
2160 psh.dwFlags = PSH_WIZARD/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
2161 psh.pszbmWatermark = NULL;
2162 psh.pszbmHeader = NULL;
2163 psh.nStartPage = 0;
2164 psh.nPages = 4;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002165
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002166 PropertySheet(&psh);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002167}
2168
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002169// subtly different from HasLocalMachinePrivs(), in that after executing
2170// an 'elevated' process, we expect this to return TRUE - but there is no
2171// such implication for HasLocalMachinePrivs
2172BOOL MyIsUserAnAdmin()
2173{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002174 typedef BOOL (WINAPI *PFNIsUserAnAdmin)();
2175 static PFNIsUserAnAdmin pfnIsUserAnAdmin = NULL;
2176 HMODULE shell32;
2177 // This function isn't guaranteed to be available (and it can't hurt
2178 // to leave the library loaded)
2179 if (0 == (shell32=LoadLibrary("shell32.dll")))
2180 return FALSE;
Serhiy Storchaka0b3ec192017-03-23 17:53:47 +02002181 if (NULL == (pfnIsUserAnAdmin=(PFNIsUserAnAdmin)GetProcAddress(shell32, "IsUserAnAdmin")))
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002182 return FALSE;
2183 return (*pfnIsUserAnAdmin)();
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002184}
2185
2186// Some magic for Vista's UAC. If there is a target_version, and
2187// if that target version is installed in the registry under
2188// HKLM, and we are not current administrator, then
2189// re-execute ourselves requesting elevation.
2190// Split into 2 functions - "should we elevate" and "spawn elevated"
2191
2192// Returns TRUE if we should spawn an elevated child
2193BOOL NeedAutoUAC()
2194{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002195 HKEY hk;
2196 char key_name[80];
2197 // no Python version info == we can't know yet.
2198 if (target_version[0] == '\0')
2199 return FALSE;
2200 // see how python is current installed
2201 wsprintf(key_name,
2202 "Software\\Python\\PythonCore\\%s\\InstallPath",
2203 target_version);
2204 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2205 key_name, 0, KEY_READ, &hk))
2206 return FALSE;
2207 RegCloseKey(hk);
2208 // Python is installed in HKLM - we must elevate.
2209 return TRUE;
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002210}
2211
2212// Spawn ourself as an elevated application. On failure, a message is
2213// displayed to the user - but this app will always terminate, even
2214// on error.
2215void SpawnUAC()
2216{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002217 // interesting failure scenario that has been seen: initial executable
2218 // runs from a network drive - but once elevated, that network share
2219 // isn't seen, and ShellExecute fails with SE_ERR_ACCESSDENIED.
2220 int ret = (int)ShellExecute(0, "runas", modulename, "", NULL,
2221 SW_SHOWNORMAL);
2222 if (ret <= 32) {
2223 char msg[128];
2224 wsprintf(msg, "Failed to start elevated process (ShellExecute returned %d)", ret);
2225 MessageBox(0, msg, "Setup", MB_OK | MB_ICONERROR);
2226 }
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002227}
2228
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002229int DoInstall(void)
2230{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002231 char ini_buffer[4096];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002232
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002233 /* Read installation information */
2234 GetPrivateProfileString("Setup", "title", "", ini_buffer,
2235 sizeof(ini_buffer), ini_file);
2236 unescape(title, ini_buffer, sizeof(title));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002237
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002238 GetPrivateProfileString("Setup", "info", "", ini_buffer,
2239 sizeof(ini_buffer), ini_file);
2240 unescape(info, ini_buffer, sizeof(info));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002241
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002242 GetPrivateProfileString("Setup", "build_info", "", build_info,
2243 sizeof(build_info), ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002244
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002245 pyc_compile = GetPrivateProfileInt("Setup", "target_compile", 1,
2246 ini_file);
2247 pyo_compile = GetPrivateProfileInt("Setup", "target_optimize", 1,
2248 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002249
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002250 GetPrivateProfileString("Setup", "target_version", "",
2251 target_version, sizeof(target_version),
2252 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002253
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002254 GetPrivateProfileString("metadata", "name", "",
2255 meta_name, sizeof(meta_name),
2256 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002257
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002258 GetPrivateProfileString("Setup", "install_script", "",
2259 install_script, sizeof(install_script),
2260 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002261
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002262 GetPrivateProfileString("Setup", "user_access_control", "",
2263 user_access_control, sizeof(user_access_control), ini_file);
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002264
Steve Dower332334f2016-01-16 13:54:53 -08002265 strcat(target_version, REGISTRY_SUFFIX_6432);
2266
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002267 // See if we need to do the Vista UAC magic.
2268 if (strcmp(user_access_control, "force")==0) {
Steve Dower65e4cb12014-11-22 12:54:57 -08002269 if (!MyIsUserAnAdmin()) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002270 SpawnUAC();
2271 return 0;
2272 }
2273 // already admin - keep going
2274 } else if (strcmp(user_access_control, "auto")==0) {
2275 // Check if it looks like we need UAC control, based
2276 // on how Python itself was installed.
Steve Dower65e4cb12014-11-22 12:54:57 -08002277 if (!MyIsUserAnAdmin() && NeedAutoUAC()) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002278 SpawnUAC();
2279 return 0;
2280 }
2281 } else {
2282 // display a warning about unknown values - only the developer
2283 // of the extension will see it (until they fix it!)
2284 if (user_access_control[0] && strcmp(user_access_control, "none") != 0) {
2285 MessageBox(GetFocus(), "Bad user_access_control value", "oops", MB_OK);
2286 // nothing to do.
2287 }
2288 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002289
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002290 hwndMain = CreateBackground(title);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002291
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002292 RunWizard(hwndMain);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002293
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002294 /* Clean up */
2295 UnmapViewOfFile(arc_data);
2296 if (ini_file)
2297 DeleteFile(ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002298
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002299 if (hBitmap)
2300 DeleteObject(hBitmap);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002301
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002302 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002303}
2304
2305/*********************** uninstall section ******************************/
2306
2307static int compare(const void *p1, const void *p2)
2308{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002309 return strcmp(*(char **)p2, *(char **)p1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002310}
2311
2312/*
2313 * Commit suicide (remove the uninstaller itself).
2314 *
2315 * Create a batch file to first remove the uninstaller
2316 * (will succeed after it has finished), then the batch file itself.
2317 *
2318 * This technique has been demonstrated by Jeff Richter,
2319 * MSJ 1/1996
2320 */
2321void remove_exe(void)
2322{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002323 char exename[_MAX_PATH];
2324 char batname[_MAX_PATH];
2325 FILE *fp;
2326 STARTUPINFO si;
2327 PROCESS_INFORMATION pi;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002328
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002329 GetModuleFileName(NULL, exename, sizeof(exename));
2330 sprintf(batname, "%s.bat", exename);
2331 fp = fopen(batname, "w");
2332 fprintf(fp, ":Repeat\n");
2333 fprintf(fp, "del \"%s\"\n", exename);
2334 fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
2335 fprintf(fp, "del \"%s\"\n", batname);
2336 fclose(fp);
2337
2338 ZeroMemory(&si, sizeof(si));
2339 si.cb = sizeof(si);
2340 si.dwFlags = STARTF_USESHOWWINDOW;
2341 si.wShowWindow = SW_HIDE;
2342 if (CreateProcess(NULL,
2343 batname,
2344 NULL,
2345 NULL,
2346 FALSE,
2347 CREATE_SUSPENDED | IDLE_PRIORITY_CLASS,
2348 NULL,
2349 "\\",
2350 &si,
2351 &pi)) {
2352 SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE);
2353 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
2354 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
2355 CloseHandle(pi.hProcess);
2356 ResumeThread(pi.hThread);
2357 CloseHandle(pi.hThread);
2358 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002359}
2360
2361void DeleteRegistryKey(char *string)
2362{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002363 char *keyname;
2364 char *subkeyname;
2365 char *delim;
2366 HKEY hKey;
2367 long result;
2368 char *line;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002369
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002370 line = strdup(string); /* so we can change it */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002371
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002372 keyname = strchr(line, '[');
2373 if (!keyname)
2374 return;
2375 ++keyname;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002376
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002377 subkeyname = strchr(keyname, ']');
2378 if (!subkeyname)
2379 return;
2380 *subkeyname++='\0';
2381 delim = strchr(subkeyname, '\n');
2382 if (delim)
2383 *delim = '\0';
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002384
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002385 result = RegOpenKeyEx(hkey_root,
2386 keyname,
2387 0,
2388 KEY_WRITE,
2389 &hKey);
2390
2391 if (result != ERROR_SUCCESS)
2392 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2393 else {
2394 result = RegDeleteKey(hKey, subkeyname);
2395 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
2396 MessageBox(GetFocus(), string, "Could not delete key", MB_OK);
2397 RegCloseKey(hKey);
2398 }
2399 free(line);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002400}
2401
2402void DeleteRegistryValue(char *string)
2403{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002404 char *keyname;
2405 char *valuename;
2406 char *value;
2407 HKEY hKey;
2408 long result;
2409 char *line;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002410
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002411 line = strdup(string); /* so we can change it */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002412
2413/* Format is 'Reg DB Value: [key]name=value' */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002414 keyname = strchr(line, '[');
2415 if (!keyname)
2416 return;
2417 ++keyname;
2418 valuename = strchr(keyname, ']');
2419 if (!valuename)
2420 return;
2421 *valuename++ = '\0';
2422 value = strchr(valuename, '=');
2423 if (!value)
2424 return;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002425
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002426 *value++ = '\0';
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002427
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002428 result = RegOpenKeyEx(hkey_root,
2429 keyname,
2430 0,
2431 KEY_WRITE,
2432 &hKey);
2433 if (result != ERROR_SUCCESS)
2434 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2435 else {
2436 result = RegDeleteValue(hKey, valuename);
2437 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
2438 MessageBox(GetFocus(), string, "Could not delete value", MB_OK);
2439 RegCloseKey(hKey);
2440 }
2441 free(line);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002442}
2443
2444BOOL MyDeleteFile(char *line)
2445{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002446 char *pathname = strchr(line, ':');
2447 if (!pathname)
2448 return FALSE;
2449 ++pathname;
2450 while (isspace(*pathname))
2451 ++pathname;
2452 return DeleteFile(pathname);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002453}
2454
2455BOOL MyRemoveDirectory(char *line)
2456{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002457 char *pathname = strchr(line, ':');
2458 if (!pathname)
2459 return FALSE;
2460 ++pathname;
2461 while (isspace(*pathname))
2462 ++pathname;
2463 return RemoveDirectory(pathname);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002464}
2465
2466BOOL Run_RemoveScript(char *line)
2467{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002468 char *dllname;
2469 char *scriptname;
2470 static char lastscript[MAX_PATH];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002471
2472/* Format is 'Run Scripts: [pythondll]scriptname' */
2473/* XXX Currently, pythondll carries no path!!! */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002474 dllname = strchr(line, '[');
2475 if (!dllname)
2476 return FALSE;
2477 ++dllname;
2478 scriptname = strchr(dllname, ']');
2479 if (!scriptname)
2480 return FALSE;
2481 *scriptname++ = '\0';
2482 /* this function may be called more than one time with the same
2483 script, only run it one time */
2484 if (strcmp(lastscript, scriptname)) {
2485 char *argv[3] = {NULL, "-remove", NULL};
2486 char *buffer = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002487
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002488 argv[0] = scriptname;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002489
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002490 if (0 != run_installscript(scriptname, 2, argv, &buffer))
2491 fprintf(stderr, "*** Could not run installation script ***");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002492
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002493 if (buffer && buffer[0])
2494 MessageBox(GetFocus(), buffer, "uninstall-script", MB_OK);
2495 free(buffer);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002496
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002497 strcpy(lastscript, scriptname);
2498 }
2499 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002500}
2501
2502int DoUninstall(int argc, char **argv)
2503{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002504 FILE *logfile;
2505 char buffer[4096];
2506 int nLines = 0;
2507 int i;
2508 char *cp;
2509 int nFiles = 0;
2510 int nDirs = 0;
2511 int nErrors = 0;
2512 char **lines;
2513 int lines_buffer_size = 10;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002514
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002515 if (argc != 3) {
2516 MessageBox(NULL,
2517 "Wrong number of args",
2518 NULL,
2519 MB_OK);
2520 return 1; /* Error */
2521 }
2522 if (strcmp(argv[1], "-u")) {
2523 MessageBox(NULL,
2524 "2. arg is not -u",
2525 NULL,
2526 MB_OK);
2527 return 1; /* Error */
2528 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002529
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002530 logfile = fopen(argv[2], "r");
2531 if (!logfile) {
2532 MessageBox(NULL,
2533 "could not open logfile",
2534 NULL,
2535 MB_OK);
2536 return 1; /* Error */
2537 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002538
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002539 lines = (char **)malloc(sizeof(char *) * lines_buffer_size);
2540 if (!lines)
2541 return SystemError(0, "Out of memory");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002542
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002543 /* Read the whole logfile, realloacting the buffer */
2544 while (fgets(buffer, sizeof(buffer), logfile)) {
2545 int len = strlen(buffer);
2546 /* remove trailing white space */
2547 while (isspace(buffer[len-1]))
2548 len -= 1;
2549 buffer[len] = '\0';
2550 lines[nLines++] = strdup(buffer);
2551 if (nLines >= lines_buffer_size) {
2552 lines_buffer_size += 10;
2553 lines = (char **)realloc(lines,
2554 sizeof(char *) * lines_buffer_size);
2555 if (!lines)
2556 return SystemError(0, "Out of memory");
2557 }
2558 }
2559 fclose(logfile);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002560
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002561 /* Sort all the lines, so that highest 3-digit codes are first */
2562 qsort(&lines[0], nLines, sizeof(char *),
2563 compare);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002564
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002565 if (IDYES != MessageBox(NULL,
2566 "Are you sure you want to remove\n"
2567 "this package from your computer?",
2568 "Please confirm",
2569 MB_YESNO | MB_ICONQUESTION))
2570 return 0;
2571
2572 hkey_root = HKEY_LOCAL_MACHINE;
2573 cp = "";
2574 for (i = 0; i < nLines; ++i) {
2575 /* Ignore duplicate lines */
2576 if (strcmp(cp, lines[i])) {
2577 int ign;
2578 cp = lines[i];
2579 /* Parse the lines */
2580 if (2 == sscanf(cp, "%d Root Key: %s", &ign, &buffer)) {
2581 if (strcmp(buffer, "HKEY_CURRENT_USER")==0)
2582 hkey_root = HKEY_CURRENT_USER;
2583 else {
2584 // HKLM - check they have permissions.
2585 if (!HasLocalMachinePrivs()) {
2586 MessageBox(GetFocus(),
2587 "You do not seem to have sufficient access rights\n"
2588 "on this machine to uninstall this software",
2589 NULL,
2590 MB_OK | MB_ICONSTOP);
2591 return 1; /* Error */
2592 }
2593 }
2594 } else if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
2595 if (MyRemoveDirectory(cp))
2596 ++nDirs;
2597 else {
2598 int code = GetLastError();
2599 if (code != 2 && code != 3) { /* file or path not found */
2600 ++nErrors;
2601 }
2602 }
2603 } else if (2 == sscanf(cp, "%d File Copy: %s", &ign, &buffer)) {
2604 if (MyDeleteFile(cp))
2605 ++nFiles;
2606 else {
2607 int code = GetLastError();
2608 if (code != 2 && code != 3) { /* file or path not found */
2609 ++nErrors;
2610 }
2611 }
2612 } else if (2 == sscanf(cp, "%d File Overwrite: %s", &ign, &buffer)) {
2613 if (MyDeleteFile(cp))
2614 ++nFiles;
2615 else {
2616 int code = GetLastError();
2617 if (code != 2 && code != 3) { /* file or path not found */
2618 ++nErrors;
2619 }
2620 }
2621 } else if (2 == sscanf(cp, "%d Reg DB Key: %s", &ign, &buffer)) {
2622 DeleteRegistryKey(cp);
2623 } else if (2 == sscanf(cp, "%d Reg DB Value: %s", &ign, &buffer)) {
2624 DeleteRegistryValue(cp);
2625 } else if (2 == sscanf(cp, "%d Run Script: %s", &ign, &buffer)) {
2626 Run_RemoveScript(cp);
2627 }
2628 }
2629 }
2630
2631 if (DeleteFile(argv[2])) {
2632 ++nFiles;
2633 } else {
2634 ++nErrors;
2635 SystemError(GetLastError(), argv[2]);
2636 }
2637 if (nErrors)
2638 wsprintf(buffer,
2639 "%d files and %d directories removed\n"
2640 "%d files or directories could not be removed",
2641 nFiles, nDirs, nErrors);
2642 else
2643 wsprintf(buffer, "%d files and %d directories removed",
2644 nFiles, nDirs);
2645 MessageBox(NULL, buffer, "Uninstall Finished!",
2646 MB_OK | MB_ICONINFORMATION);
2647 remove_exe();
2648 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002649}
2650
2651int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002652 LPSTR lpszCmdLine, INT nCmdShow)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002653{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002654 extern int __argc;
2655 extern char **__argv;
2656 char *basename;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002657
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002658 GetModuleFileName(NULL, modulename, sizeof(modulename));
2659 GetModuleFileNameW(NULL, wmodulename, sizeof(wmodulename)/sizeof(wmodulename[0]));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002660
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002661 /* Map the executable file to memory */
2662 arc_data = MapExistingFile(modulename, &arc_size);
2663 if (!arc_data) {
2664 SystemError(GetLastError(), "Could not open archive");
2665 return 1;
2666 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002667
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002668 /* OK. So this program can act as installer (self-extracting
2669 * zip-file, or as uninstaller when started with '-u logfile'
2670 * command line flags.
2671 *
2672 * The installer is usually started without command line flags,
2673 * and the uninstaller is usually started with the '-u logfile'
2674 * flag. What to do if some innocent user double-clicks the
2675 * exe-file?
2676 * The following implements a defensive strategy...
2677 */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002678
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002679 /* Try to extract the configuration data into a temporary file */
2680 if (ExtractInstallData(arc_data, arc_size, &exe_size,
2681 &ini_file, &pre_install_script))
2682 return DoInstall();
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002683
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002684 if (!ini_file && __argc > 1) {
2685 return DoUninstall(__argc, __argv);
2686 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002687
2688
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002689 basename = strrchr(modulename, '\\');
2690 if (basename)
2691 ++basename;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002692
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002693 /* Last guess about the purpose of this program */
2694 if (basename && (0 == strncmp(basename, "Remove", 6)))
2695 SystemError(0, "This program is normally started by windows");
2696 else
2697 SystemError(0, "Setup program invalid or damaged");
2698 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002699}