blob: 17cc30d25cf8f6931e7807e2aace1671b37b8256 [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
Mark Hammondf9bfdd82004-07-02 23:53:16 +0000634static PyObject *GetRootHKey(PyObject *self)
635{
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
641typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000642
643PyMethodDef meth[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000644 {"create_shortcut", CreateShortcut, METH_VARARGS, NULL},
645 {"get_special_folder_path", GetSpecialFolderPath, METH_VARARGS, NULL},
646 {"get_root_hkey", (PyCFunction)GetRootHKey, METH_NOARGS, NULL},
647 {"file_created", FileCreated, METH_VARARGS, NULL},
648 {"directory_created", DirectoryCreated, METH_VARARGS, NULL},
649 {"message_box", PyMessageBox, METH_VARARGS, NULL},
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000650};
651
Thomas Heller48340392004-06-18 17:03:38 +0000652static HINSTANCE LoadPythonDll(char *fname)
653{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000654 char fullpath[_MAX_PATH];
655 LONG size = sizeof(fullpath);
656 char subkey_name[80];
657 char buffer[260 + 12];
658 HINSTANCE h;
Thomas Heller8abe7bf2005-02-03 20:11:28 +0000659
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000660 /* make sure PYTHONHOME is set, to that sys.path is initialized correctly */
661 wsprintf(buffer, "PYTHONHOME=%s", python_dir);
662 _putenv(buffer);
663 h = LoadLibrary(fname);
664 if (h)
665 return h;
666 wsprintf(subkey_name,
Steve Dower332334f2016-01-16 13:54:53 -0800667 "SOFTWARE\\Python\\PythonCore\\%d.%d%s\\InstallPath",
668 py_major, py_minor, REGISTRY_SUFFIX_6432);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000669 if (ERROR_SUCCESS != RegQueryValue(HKEY_CURRENT_USER, subkey_name,
670 fullpath, &size) &&
671 ERROR_SUCCESS != RegQueryValue(HKEY_LOCAL_MACHINE, subkey_name,
672 fullpath, &size))
673 return NULL;
674 strcat(fullpath, "\\");
675 strcat(fullpath, fname);
Steve Dower332334f2016-01-16 13:54:53 -0800676 // We use LOAD_WITH_ALTERED_SEARCH_PATH to ensure any dependent DLLs
677 // next to the Python DLL (eg, the CRT DLL) are also loaded.
678 return LoadLibraryEx(fullpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
Thomas Heller48340392004-06-18 17:03:38 +0000679}
680
Thomas Hellera19cdad2004-02-20 14:43:21 +0000681static int prepare_script_environment(HINSTANCE hPython)
682{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000683 PyObject *mod;
684 DECLPROC(hPython, PyObject *, PyImport_ImportModule, (char *));
685 DECLPROC(hPython, int, PyObject_SetAttrString, (PyObject *, char *, PyObject *));
686 DECLPROC(hPython, PyObject *, PyObject_GetAttrString, (PyObject *, char *));
687 DECLPROC(hPython, PyObject *, PyCFunction_New, (PyMethodDef *, PyObject *));
688 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
689 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
690 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
691 DECLPROC(hPython, PyObject *, PyLong_FromVoidPtr, (void *));
692 if (!PyImport_ImportModule || !PyObject_GetAttrString ||
693 !PyObject_SetAttrString || !PyCFunction_New)
694 return 1;
695 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
696 return 1;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000697
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000698 mod = PyImport_ImportModule("builtins");
699 if (mod) {
700 int i;
701 g_PyExc_ValueError = PyObject_GetAttrString(mod, "ValueError");
702 g_PyExc_OSError = PyObject_GetAttrString(mod, "OSError");
703 for (i = 0; i < DIM(meth); ++i) {
704 PyObject_SetAttrString(mod, meth[i].ml_name,
705 PyCFunction_New(&meth[i], NULL));
706 }
707 }
708 g_Py_BuildValue = Py_BuildValue;
709 g_PyArg_ParseTuple = PyArg_ParseTuple;
710 g_PyErr_Format = PyErr_Format;
711 g_PyLong_FromVoidPtr = PyLong_FromVoidPtr;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000712
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000713 return 0;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000714}
715
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000716/*
717 * This function returns one of the following error codes:
718 * 1 if the Python-dll does not export the functions we need
719 * 2 if no install-script is specified in pathname
720 * 3 if the install-script file could not be opened
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000721 * the return value of PyRun_SimpleString() or Py_FinalizeEx() otherwise,
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000722 * which is 0 if everything is ok, -1 if an exception had occurred
723 * in the install-script.
724 */
725
726static int
Mark Hammond6d0e9752009-01-29 12:36:50 +0000727do_run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000728{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000729 int fh, result, i;
730 static wchar_t *wargv[256];
731 DECLPROC(hPython, void, Py_Initialize, (void));
732 DECLPROC(hPython, int, PySys_SetArgv, (int, wchar_t **));
733 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000734 DECLPROC(hPython, int, Py_FinalizeEx, (void));
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000735 DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
736 DECLPROC(hPython, PyObject *, PyCFunction_New,
737 (PyMethodDef *, PyObject *));
738 DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
739 DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000740
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000741 if (!Py_Initialize || !PySys_SetArgv
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000742 || !PyRun_SimpleString || !Py_FinalizeEx)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000743 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000744
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000745 if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
746 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000747
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000748 if (!PyCFunction_New || !PyArg_ParseTuple || !PyErr_Format)
749 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000750
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000751 if (pathname == NULL || pathname[0] == '\0')
752 return 2;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000753
Victor Stinnerdaf45552013-08-28 00:53:59 +0200754 fh = open(pathname, _O_RDONLY | O_NOINHERIT);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000755 if (-1 == fh) {
756 fprintf(stderr, "Could not open postinstall-script %s\n",
757 pathname);
758 return 3;
759 }
Mark Hammond6d0e9752009-01-29 12:36:50 +0000760
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000761 SetDlgItemText(hDialog, IDC_INFO, "Running Script...");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000762
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000763 Py_Initialize();
Mark Hammond891f2632009-01-29 13:08:01 +0000764
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000765 prepare_script_environment(hPython);
766 // widen the argv array for py3k.
767 memset(wargv, 0, sizeof(wargv));
768 for (i=0;i<argc;i++)
769 wargv[i] = argv[i] ? widen_string(argv[i]) : NULL;
770 PySys_SetArgv(argc, wargv);
771 // free the strings we just widened.
772 for (i=0;i<argc;i++)
773 if (wargv[i])
774 free(wargv[i]);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000775
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000776 result = 3;
777 {
778 struct _stat statbuf;
779 if(0 == _fstat(fh, &statbuf)) {
780 char *script = alloca(statbuf.st_size + 5);
781 int n = read(fh, script, statbuf.st_size);
782 if (n > 0) {
783 script[n] = '\n';
784 script[n+1] = 0;
785 result = PyRun_SimpleString(script);
786 }
787 }
788 }
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000789 if (Py_FinalizeEx() < 0) {
790 result = -1;
791 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000792
793 close(fh);
794 return result;
Mark Hammond6d0e9752009-01-29 12:36:50 +0000795}
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000796
Mark Hammond6d0e9752009-01-29 12:36:50 +0000797static int
798run_installscript(char *pathname, int argc, char **argv, char **pOutput)
799{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000800 HINSTANCE hPython;
801 int result = 1;
802 int out_buf_size;
803 HANDLE redirected, old_stderr, old_stdout;
804 char *tempname;
Mark Hammond6d0e9752009-01-29 12:36:50 +0000805
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000806 *pOutput = NULL;
Mark Hammond6d0e9752009-01-29 12:36:50 +0000807
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000808 tempname = tempnam(NULL, NULL);
809 // We use a static CRT while the Python version we load uses
Ezio Melotti13925002011-03-16 11:05:33 +0200810 // the CRT from one of various possible DLLs. As a result we
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000811 // need to redirect the standard handles using the API rather
812 // than the CRT.
813 redirected = CreateFile(
814 tempname,
815 GENERIC_WRITE | GENERIC_READ,
816 FILE_SHARE_READ,
817 NULL,
818 CREATE_ALWAYS,
819 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
820 NULL);
821 old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
822 old_stderr = GetStdHandle(STD_ERROR_HANDLE);
823 SetStdHandle(STD_OUTPUT_HANDLE, redirected);
824 SetStdHandle(STD_ERROR_HANDLE, redirected);
Mark Hammond6d0e9752009-01-29 12:36:50 +0000825
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000826 hPython = LoadPythonDll(pythondll);
827 if (hPython) {
828 result = do_run_installscript(hPython, pathname, argc, argv);
829 FreeLibrary(hPython);
830 } else {
831 fprintf(stderr, "*** Could not load Python ***");
832 }
833 SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
834 SetStdHandle(STD_ERROR_HANDLE, old_stderr);
835 out_buf_size = min(GetFileSize(redirected, NULL), 4096);
836 *pOutput = malloc(out_buf_size+1);
837 if (*pOutput) {
838 DWORD nread = 0;
839 SetFilePointer(redirected, 0, 0, FILE_BEGIN);
840 ReadFile(redirected, *pOutput, out_buf_size, &nread, NULL);
841 (*pOutput)[nread] = '\0';
842 }
843 CloseHandle(redirected);
844 DeleteFile(tempname);
845 return result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000846}
847
Thomas Hellera19cdad2004-02-20 14:43:21 +0000848static int do_run_simple_script(HINSTANCE hPython, char *script)
849{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000850 int rc;
851 DECLPROC(hPython, void, Py_Initialize, (void));
852 DECLPROC(hPython, void, Py_SetProgramName, (wchar_t *));
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000853 DECLPROC(hPython, int, Py_FinalizeEx, (void));
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000854 DECLPROC(hPython, int, PyRun_SimpleString, (char *));
855 DECLPROC(hPython, void, PyErr_Print, (void));
Thomas Hellera19cdad2004-02-20 14:43:21 +0000856
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000857 if (!Py_Initialize || !Py_SetProgramName || !Py_FinalizeEx ||
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000858 !PyRun_SimpleString || !PyErr_Print)
859 return -1;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000860
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000861 Py_SetProgramName(wmodulename);
862 Py_Initialize();
863 prepare_script_environment(hPython);
864 rc = PyRun_SimpleString(script);
865 if (rc)
866 PyErr_Print();
Martin Panterb4ce1fc2015-11-30 03:18:29 +0000867 if (Py_FinalizeEx() < 0) {
868 rc = -1;
869 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000870 return rc;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000871}
872
873static int run_simple_script(char *script)
874{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000875 int rc;
876 HINSTANCE hPython;
877 char *tempname = tempnam(NULL, NULL);
878 // Redirect output using win32 API - see comments above...
879 HANDLE redirected = CreateFile(
880 tempname,
881 GENERIC_WRITE | GENERIC_READ,
882 FILE_SHARE_READ,
883 NULL,
884 CREATE_ALWAYS,
885 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
886 NULL);
887 HANDLE old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
888 HANDLE old_stderr = GetStdHandle(STD_ERROR_HANDLE);
889 SetStdHandle(STD_OUTPUT_HANDLE, redirected);
890 SetStdHandle(STD_ERROR_HANDLE, redirected);
Thomas Hellera19cdad2004-02-20 14:43:21 +0000891
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000892 hPython = LoadPythonDll(pythondll);
893 if (!hPython) {
894 char reason[128];
895 wsprintf(reason, "Can't load Python for pre-install script (%d)", GetLastError());
896 set_failure_reason(reason);
897 return -1;
898 }
899 rc = do_run_simple_script(hPython, script);
900 FreeLibrary(hPython);
901 SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
902 SetStdHandle(STD_ERROR_HANDLE, old_stderr);
903 /* We only care about the output when we fail. If the script works
904 OK, then we discard it
905 */
906 if (rc) {
907 int err_buf_size;
908 char *err_buf;
909 const char *prefix = "Running the pre-installation script failed\r\n";
910 int prefix_len = strlen(prefix);
911 err_buf_size = GetFileSize(redirected, NULL);
912 if (err_buf_size==INVALID_FILE_SIZE) // an error - let's try anyway...
913 err_buf_size = 4096;
914 err_buf = malloc(prefix_len + err_buf_size + 1);
915 if (err_buf) {
916 DWORD n = 0;
917 strcpy(err_buf, prefix);
918 SetFilePointer(redirected, 0, 0, FILE_BEGIN);
919 ReadFile(redirected, err_buf+prefix_len, err_buf_size, &n, NULL);
920 err_buf[prefix_len+n] = '\0';
921 set_failure_reason(err_buf);
922 free(err_buf);
923 } else {
924 set_failure_reason("Out of memory!");
925 }
926 }
927 CloseHandle(redirected);
928 DeleteFile(tempname);
929 return rc;
Thomas Hellera19cdad2004-02-20 14:43:21 +0000930}
931
932
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000933static BOOL SystemError(int error, char *msg)
934{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000935 char Buffer[1024];
936 int n;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000937
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000938 if (error) {
939 LPVOID lpMsgBuf;
940 FormatMessage(
941 FORMAT_MESSAGE_ALLOCATE_BUFFER |
942 FORMAT_MESSAGE_FROM_SYSTEM,
943 NULL,
944 error,
945 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
946 (LPSTR)&lpMsgBuf,
947 0,
948 NULL
949 );
950 strncpy(Buffer, lpMsgBuf, sizeof(Buffer));
951 LocalFree(lpMsgBuf);
952 } else
953 Buffer[0] = '\0';
954 n = lstrlen(Buffer);
955 _snprintf(Buffer+n, sizeof(Buffer)-n, msg);
956 MessageBox(hwndMain, Buffer, "Runtime Error", MB_OK | MB_ICONSTOP);
957 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000958}
959
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000960static BOOL notify (int code, char *fmt, ...)
961{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000962 char Buffer[1024];
963 va_list marker;
964 BOOL result = TRUE;
965 int a, b;
966 char *cp;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000967
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000968 va_start(marker, fmt);
969 _vsnprintf(Buffer, sizeof(Buffer), fmt, marker);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000970
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000971 switch (code) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000972/* Questions */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000973 case CAN_OVERWRITE:
974 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000975
976/* Information notification */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000977 case DIR_CREATED:
978 if (logfile)
979 fprintf(logfile, "100 Made Dir: %s\n", fmt);
980 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000981
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000982 case FILE_CREATED:
983 if (logfile)
984 fprintf(logfile, "200 File Copy: %s\n", fmt);
985 goto add_to_filelist_label;
986 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000987
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000988 case FILE_OVERWRITTEN:
989 if (logfile)
990 fprintf(logfile, "200 File Overwrite: %s\n", fmt);
991 add_to_filelist_label:
992 if ((cp = strrchr(fmt, '.')) && (0 == strcmp (cp, ".py")))
993 add_to_filelist(fmt);
994 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +0000995
996/* Error Messages */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000997 case ZLIB_ERROR:
998 MessageBox(GetFocus(), Buffer, "Error",
999 MB_OK | MB_ICONWARNING);
1000 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001001
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001002 case SYSTEM_ERROR:
1003 SystemError(GetLastError(), Buffer);
1004 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001005
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001006 case NUM_FILES:
1007 a = va_arg(marker, int);
1008 b = va_arg(marker, int);
1009 SendMessage(hDialog, WM_NUMFILES, 0, MAKELPARAM(0, a));
1010 SendMessage(hDialog, WM_NEXTFILE, b,(LPARAM)fmt);
1011 }
1012 va_end(marker);
1013
1014 return result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001015}
1016
1017static char *MapExistingFile(char *pathname, DWORD *psize)
1018{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001019 HANDLE hFile, hFileMapping;
1020 DWORD nSizeLow, nSizeHigh;
1021 char *data;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001022
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001023 hFile = CreateFile(pathname,
1024 GENERIC_READ, FILE_SHARE_READ, NULL,
1025 OPEN_EXISTING,
1026 FILE_ATTRIBUTE_NORMAL, NULL);
1027 if (hFile == INVALID_HANDLE_VALUE)
1028 return NULL;
1029 nSizeLow = GetFileSize(hFile, &nSizeHigh);
1030 hFileMapping = CreateFileMapping(hFile,
1031 NULL, PAGE_READONLY, 0, 0, NULL);
1032 CloseHandle(hFile);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001033
Gregory P. Smithb803c6c2013-03-23 16:05:36 -07001034 if (hFileMapping == NULL)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001035 return NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001036
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001037 data = MapViewOfFile(hFileMapping,
1038 FILE_MAP_READ, 0, 0, 0);
1039
1040 CloseHandle(hFileMapping);
1041 *psize = nSizeLow;
1042 return data;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001043}
1044
1045
1046static void create_bitmap(HWND hwnd)
1047{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001048 BITMAPFILEHEADER *bfh;
1049 BITMAPINFO *bi;
1050 HDC hdc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001051
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001052 if (!bitmap_bytes)
1053 return;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001054
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001055 if (hBitmap)
1056 return;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001057
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001058 hdc = GetDC(hwnd);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001059
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001060 bfh = (BITMAPFILEHEADER *)bitmap_bytes;
1061 bi = (BITMAPINFO *)(bitmap_bytes + sizeof(BITMAPFILEHEADER));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001062
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001063 hBitmap = CreateDIBitmap(hdc,
1064 &bi->bmiHeader,
1065 CBM_INIT,
1066 bitmap_bytes + bfh->bfOffBits,
1067 bi,
1068 DIB_RGB_COLORS);
1069 ReleaseDC(hwnd, hdc);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001070}
1071
Thomas Hellera19cdad2004-02-20 14:43:21 +00001072/* Extract everything we need to begin the installation. Currently this
1073 is the INI filename with install data, and the raw pre-install script
1074*/
1075static BOOL ExtractInstallData(char *data, DWORD size, int *pexe_size,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001076 char **out_ini_file, char **out_preinstall_script)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001077{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001078 /* read the end of central directory record */
1079 struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
1080 (struct eof_cdir)];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001081
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001082 int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
1083 pe->ofsCDir;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001084
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001085 int ofs = arc_start - sizeof (struct meta_data_hdr);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001086
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001087 /* read meta_data info */
1088 struct meta_data_hdr *pmd = (struct meta_data_hdr *)&data[ofs];
1089 char *src, *dst;
1090 char *ini_file;
1091 char tempdir[MAX_PATH];
Thomas Hellera19cdad2004-02-20 14:43:21 +00001092
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001093 /* ensure that if we fail, we don't have garbage out pointers */
1094 *out_ini_file = *out_preinstall_script = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001095
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001096 if (pe->tag != 0x06054b50) {
1097 return FALSE;
1098 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001099
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001100 if (pmd->tag != 0x1234567B) {
1101 return SystemError(0,
1102 "Invalid cfgdata magic number (see bdist_wininst.py)");
1103 }
1104 if (ofs < 0) {
1105 return FALSE;
1106 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001107
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001108 if (pmd->bitmap_size) {
1109 /* Store pointer to bitmap bytes */
1110 bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
1111 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001112
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001113 *pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
1114
1115 src = ((char *)pmd) - pmd->uncomp_size;
1116 ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
1117 if (!ini_file)
1118 return FALSE;
1119 if (!GetTempPath(sizeof(tempdir), tempdir)
1120 || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
1121 SystemError(GetLastError(),
1122 "Could not create temporary file");
1123 return FALSE;
1124 }
1125
1126 dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
1127 0, 0, NULL/*notify*/);
1128 if (!dst)
1129 return FALSE;
1130 /* Up to the first \0 is the INI file data. */
1131 strncpy(dst, src, pmd->uncomp_size);
1132 src += strlen(dst) + 1;
1133 /* Up to next \0 is the pre-install script */
1134 *out_preinstall_script = strdup(src);
1135 *out_ini_file = ini_file;
1136 UnmapViewOfFile(dst);
1137 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001138}
1139
1140static void PumpMessages(void)
1141{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001142 MSG msg;
1143 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1144 TranslateMessage(&msg);
1145 DispatchMessage(&msg);
1146 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001147}
1148
1149LRESULT CALLBACK
1150WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1151{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001152 HDC hdc;
1153 HFONT hFont;
1154 int h;
1155 PAINTSTRUCT ps;
1156 switch (msg) {
1157 case WM_PAINT:
1158 hdc = BeginPaint(hwnd, &ps);
1159 h = GetSystemMetrics(SM_CYSCREEN) / 10;
1160 hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
1161 0, 0, 0, 0, 0, 0, 0, "Times Roman");
1162 hFont = SelectObject(hdc, hFont);
1163 SetBkMode(hdc, TRANSPARENT);
1164 TextOut(hdc, 15, 15, title, strlen(title));
1165 SetTextColor(hdc, RGB(255, 255, 255));
1166 TextOut(hdc, 10, 10, title, strlen(title));
1167 DeleteObject(SelectObject(hdc, hFont));
1168 EndPaint(hwnd, &ps);
1169 return 0;
1170 }
1171 return DefWindowProc(hwnd, msg, wParam, lParam);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001172}
1173
1174static HWND CreateBackground(char *title)
1175{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001176 WNDCLASS wc;
1177 HWND hwnd;
1178 char buffer[4096];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001179
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001180 wc.style = CS_VREDRAW | CS_HREDRAW;
1181 wc.lpfnWndProc = WindowProc;
1182 wc.cbWndExtra = 0;
1183 wc.cbClsExtra = 0;
1184 wc.hInstance = GetModuleHandle(NULL);
1185 wc.hIcon = NULL;
1186 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1187 wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
1188 wc.lpszMenuName = NULL;
1189 wc.lpszClassName = "SetupWindowClass";
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001190
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001191 if (!RegisterClass(&wc))
1192 MessageBox(hwndMain,
1193 "Could not register window class",
1194 "Setup.exe", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001195
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001196 wsprintf(buffer, "Setup %s", title);
1197 hwnd = CreateWindow("SetupWindowClass",
1198 buffer,
1199 0,
1200 0, 0,
1201 GetSystemMetrics(SM_CXFULLSCREEN),
1202 GetSystemMetrics(SM_CYFULLSCREEN),
1203 NULL,
1204 NULL,
1205 GetModuleHandle(NULL),
1206 NULL);
1207 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
1208 UpdateWindow(hwnd);
1209 return hwnd;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001210}
1211
1212/*
1213 * Center a window on the screen
1214 */
1215static void CenterWindow(HWND hwnd)
1216{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001217 RECT rc;
1218 int w, h;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001219
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001220 GetWindowRect(hwnd, &rc);
1221 w = GetSystemMetrics(SM_CXSCREEN);
1222 h = GetSystemMetrics(SM_CYSCREEN);
1223 MoveWindow(hwnd,
1224 (w - (rc.right-rc.left))/2,
1225 (h - (rc.bottom-rc.top))/2,
1226 rc.right-rc.left, rc.bottom-rc.top, FALSE);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001227}
1228
1229#include <prsht.h>
1230
Steve Dower65e4cb12014-11-22 12:54:57 -08001231INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001232IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1233{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001234 LPNMHDR lpnm;
1235 char Buffer[4096];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001236
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001237 switch (msg) {
1238 case WM_INITDIALOG:
1239 create_bitmap(hwnd);
1240 if(hBitmap)
1241 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1242 IMAGE_BITMAP, (LPARAM)hBitmap);
1243 CenterWindow(GetParent(hwnd));
1244 wsprintf(Buffer,
1245 "This Wizard will install %s on your computer. "
1246 "Click Next to continue "
1247 "or Cancel to exit the Setup Wizard.",
1248 meta_name);
1249 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1250 SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
1251 SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
1252 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001253
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001254 case WM_NOTIFY:
1255 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001256
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001257 switch (lpnm->code) {
1258 case PSN_SETACTIVE:
1259 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
1260 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001261
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001262 case PSN_WIZNEXT:
1263 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001264
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001265 case PSN_RESET:
1266 break;
1267
1268 default:
1269 break;
1270 }
1271 }
1272 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001273}
1274
1275#ifdef USE_OTHER_PYTHON_VERSIONS
1276/* These are really private variables used to communicate
1277 * between StatusRoutine and CheckPythonExe
1278 */
1279char bound_image_dll[_MAX_PATH];
1280int bound_image_major;
1281int bound_image_minor;
1282
1283static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001284 PSTR ImageName,
1285 PSTR DllName,
1286 ULONG Va,
1287 ULONG Parameter)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001288{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001289 char fname[_MAX_PATH];
1290 int int_version;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001291
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001292 switch(reason) {
1293 case BindOutOfMemory:
1294 case BindRvaToVaFailed:
1295 case BindNoRoomInImage:
1296 case BindImportProcedureFailed:
1297 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001298
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001299 case BindImportProcedure:
1300 case BindForwarder:
1301 case BindForwarderNOT:
1302 case BindImageModified:
1303 case BindExpandFileHeaders:
1304 case BindImageComplete:
1305 case BindSymbolsNotUpdated:
1306 case BindMismatchedSymbols:
1307 case BindImportModuleFailed:
1308 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001309
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001310 case BindImportModule:
1311 if (1 == sscanf(DllName, "python%d", &int_version)) {
1312 SearchPath(NULL, DllName, NULL, sizeof(fname),
1313 fname, NULL);
1314 strcpy(bound_image_dll, fname);
1315 bound_image_major = int_version / 10;
1316 bound_image_minor = int_version % 10;
1317 OutputDebugString("BOUND ");
1318 OutputDebugString(fname);
1319 OutputDebugString("\n");
1320 }
1321 break;
1322 }
1323 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001324}
1325
1326/*
1327 */
1328static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1329{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001330 void (__cdecl * Py_Initialize)(void);
1331 void (__cdecl * Py_SetProgramName)(char *);
1332 void (__cdecl * Py_Finalize)(void);
1333 void* (__cdecl * PySys_GetObject)(char *);
1334 void (__cdecl * PySys_SetArgv)(int, char **);
1335 char* (__cdecl * Py_GetPrefix)(void);
1336 char* (__cdecl * Py_GetPath)(void);
1337 HINSTANCE hPython;
1338 LPSTR prefix = NULL;
1339 int (__cdecl * PyRun_SimpleString)(char *);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001340
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001341 {
1342 char Buffer[256];
1343 wsprintf(Buffer, "PYTHONHOME=%s", exe);
1344 *strrchr(Buffer, '\\') = '\0';
1345// MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1346 _putenv(Buffer);
1347 _putenv("PYTHONPATH=");
1348 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001349
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001350 hPython = LoadLibrary(dll);
1351 if (!hPython)
1352 return NULL;
1353 Py_Initialize = (void (*)(void))GetProcAddress
1354 (hPython,"Py_Initialize");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001355
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001356 PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1357 (hPython,"PySys_SetArgv");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001358
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001359 PyRun_SimpleString = (int (*)(char *))GetProcAddress
1360 (hPython,"PyRun_SimpleString");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001361
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001362 Py_SetProgramName = (void (*)(char *))GetProcAddress
1363 (hPython,"Py_SetProgramName");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001364
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001365 PySys_GetObject = (void* (*)(char *))GetProcAddress
1366 (hPython,"PySys_GetObject");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001367
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001368 Py_GetPrefix = (char * (*)(void))GetProcAddress
1369 (hPython,"Py_GetPrefix");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001370
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001371 Py_GetPath = (char * (*)(void))GetProcAddress
1372 (hPython,"Py_GetPath");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001373
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001374 Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1375 "Py_Finalize");
1376 Py_SetProgramName(exe);
1377 Py_Initialize();
1378 PySys_SetArgv(1, &exe);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001379
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001380 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1381 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001382
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001383 Py_Finalize();
1384 FreeLibrary(hPython);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001385
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001386 return prefix;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001387}
1388
1389static BOOL
1390CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1391{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001392 bound_image_dll[0] = '\0';
1393 if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1394 pathname,
1395 NULL,
1396 NULL,
1397 StatusRoutine))
1398 return SystemError(0, "Could not bind image");
1399 if (bound_image_dll[0] == '\0')
1400 return SystemError(0, "Does not seem to be a python executable");
1401 *pmajor = bound_image_major;
1402 *pminor = bound_image_minor;
1403 if (version && *version) {
1404 char core_version[12];
1405 wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1406 if (strcmp(version, core_version))
1407 return SystemError(0, "Wrong Python version");
1408 }
1409 get_sys_prefix(pathname, bound_image_dll);
1410 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001411}
1412
1413/*
1414 * Browse for other python versions. Insert it into the listbox specified
1415 * by hwnd. version, if not NULL or empty, is the version required.
1416 */
1417static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1418{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001419 char vers_name[_MAX_PATH + 80];
1420 DWORD itemindex;
1421 OPENFILENAME of;
1422 char pathname[_MAX_PATH];
1423 DWORD result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001424
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001425 strcpy(pathname, "python.exe");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001426
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001427 memset(&of, 0, sizeof(of));
1428 of.lStructSize = sizeof(OPENFILENAME);
1429 of.hwndOwner = GetParent(hwnd);
1430 of.hInstance = NULL;
1431 of.lpstrFilter = "python.exe\0python.exe\0";
1432 of.lpstrCustomFilter = NULL;
1433 of.nMaxCustFilter = 0;
1434 of.nFilterIndex = 1;
1435 of.lpstrFile = pathname;
1436 of.nMaxFile = sizeof(pathname);
1437 of.lpstrFileTitle = NULL;
1438 of.nMaxFileTitle = 0;
1439 of.lpstrInitialDir = NULL;
1440 of.lpstrTitle = "Python executable";
1441 of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1442 of.lpstrDefExt = "exe";
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001443
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001444 result = GetOpenFileName(&of);
1445 if (result) {
1446 int major, minor;
1447 if (!CheckPythonExe(pathname, version, &major, &minor)) {
1448 return FALSE;
1449 }
1450 *strrchr(pathname, '\\') = '\0';
1451 wsprintf(vers_name, "Python Version %d.%d in %s",
1452 major, minor, pathname);
1453 itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1454 (LPARAM)(LPSTR)vers_name);
1455 SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1456 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1457 (LPARAM)(LPSTR)strdup(pathname));
1458 return TRUE;
1459 }
1460 return FALSE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001461}
1462#endif /* USE_OTHER_PYTHON_VERSIONS */
1463
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001464typedef struct _InstalledVersionInfo {
1465 char prefix[MAX_PATH+1]; // sys.prefix directory.
1466 HKEY hkey; // Is this Python in HKCU or HKLM?
1467} InstalledVersionInfo;
1468
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001469
1470/*
1471 * Fill the listbox specified by hwnd with all python versions found
1472 * in the registry. version, if not NULL or empty, is the version
1473 * required.
1474 */
1475static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1476{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001477 DWORD index = 0;
1478 char core_version[80];
1479 HKEY hKey;
1480 BOOL result = TRUE;
1481 DWORD bufsize;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001482
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001483 if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1484 "Software\\Python\\PythonCore",
1485 0, KEY_READ, &hKey))
1486 return FALSE;
1487 bufsize = sizeof(core_version);
1488 while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1489 core_version, &bufsize, NULL,
1490 NULL, NULL, NULL)) {
1491 char subkey_name[80], vers_name[80];
1492 int itemindex;
1493 DWORD value_size;
1494 HKEY hk;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001495
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001496 bufsize = sizeof(core_version);
1497 ++index;
1498 if (version && *version && strcmp(version, core_version))
1499 continue;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001500
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001501 wsprintf(vers_name, "Python Version %s (found in registry)",
1502 core_version);
1503 wsprintf(subkey_name,
1504 "Software\\Python\\PythonCore\\%s\\InstallPath",
1505 core_version);
1506 if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
1507 InstalledVersionInfo *ivi =
1508 (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
1509 value_size = sizeof(ivi->prefix);
1510 if (ivi &&
1511 ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
1512 ivi->prefix, &value_size)) {
1513 itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
1514 (LPARAM)(LPSTR)vers_name);
1515 ivi->hkey = hkRoot;
1516 SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1517 (LPARAM)(LPSTR)ivi);
1518 }
1519 RegCloseKey(hk);
1520 }
1521 }
1522 RegCloseKey(hKey);
1523 return result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001524}
1525
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001526/* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1527BOOL HasLocalMachinePrivs()
1528{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001529 HKEY hKey;
1530 DWORD result;
1531 static char KeyName[] =
1532 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001533
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001534 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1535 KeyName,
1536 0,
1537 KEY_CREATE_SUB_KEY,
1538 &hKey);
1539 if (result==0)
1540 RegCloseKey(hKey);
1541 return result==0;
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001542}
1543
1544// Check the root registry key to use - either HKLM or HKCU.
1545// If Python is installed in HKCU, then our extension also must be installed
1546// in HKCU - as Python won't be available for other users, we shouldn't either
1547// (and will fail if we are!)
1548// If Python is installed in HKLM, then we will also prefer to use HKLM, but
1549// this may not be possible - so we silently fall back to HKCU.
1550//
1551// We assume hkey_root is already set to where Python itself is installed.
1552void CheckRootKey(HWND hwnd)
1553{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001554 if (hkey_root==HKEY_CURRENT_USER) {
1555 ; // as above, always install ourself in HKCU too.
1556 } else if (hkey_root==HKEY_LOCAL_MACHINE) {
1557 // Python in HKLM, but we may or may not have permissions there.
1558 // Open the uninstall key with 'create' permissions - if this fails,
1559 // we don't have permission.
1560 if (!HasLocalMachinePrivs())
1561 hkey_root = HKEY_CURRENT_USER;
1562 } else {
1563 MessageBox(hwnd, "Don't know Python's installation type",
1564 "Strange", MB_OK | MB_ICONSTOP);
1565 /* Default to wherever they can, but preferring HKLM */
1566 hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1567 }
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001568}
1569
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001570/* Return the installation scheme depending on Python version number */
1571SCHEME *GetScheme(int major, int minor)
1572{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001573 if (major > 2)
1574 return new_scheme;
1575 else if((major == 2) && (minor >= 2))
1576 return new_scheme;
1577 return old_scheme;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001578}
1579
Steve Dower65e4cb12014-11-22 12:54:57 -08001580INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001581SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1582{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001583 LPNMHDR lpnm;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001584
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001585 switch (msg) {
1586 case WM_INITDIALOG:
1587 if (hBitmap)
1588 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1589 IMAGE_BITMAP, (LPARAM)hBitmap);
1590 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1591 HKEY_LOCAL_MACHINE, target_version);
1592 GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1593 HKEY_CURRENT_USER, target_version);
1594 { /* select the last entry which is the highest python
1595 version found */
1596 int count;
1597 count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1598 LB_GETCOUNT, 0, 0);
1599 if (count && count != LB_ERR)
1600 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1601 count-1, 0);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001602
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001603 /* If a specific Python version is required,
1604 * display a prominent notice showing this fact.
1605 */
1606 if (target_version && target_version[0]) {
1607 char buffer[4096];
1608 wsprintf(buffer,
1609 "Python %s is required for this package. "
1610 "Select installation to use:",
1611 target_version);
1612 SetDlgItemText(hwnd, IDC_TITLE, buffer);
1613 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001614
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001615 if (count == 0) {
1616 char Buffer[4096];
1617 char *msg;
1618 if (target_version && target_version[0]) {
1619 wsprintf(Buffer,
1620 "Python version %s required, which was not found"
1621 " in the registry.", target_version);
1622 msg = Buffer;
1623 } else
1624 msg = "No Python installation found in the registry.";
1625 MessageBox(hwnd, msg, "Cannot install",
1626 MB_OK | MB_ICONSTOP);
1627 }
1628 }
1629 goto UpdateInstallDir;
1630 break;
1631
1632 case WM_COMMAND:
1633 switch (LOWORD(wParam)) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001634/*
1635 case IDC_OTHERPYTHON:
1636 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1637 target_version))
1638 goto UpdateInstallDir;
1639 break;
1640*/
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001641 case IDC_VERSIONS_LIST:
1642 switch (HIWORD(wParam)) {
1643 int id;
1644 case LBN_SELCHANGE:
1645 UpdateInstallDir:
1646 PropSheet_SetWizButtons(GetParent(hwnd),
1647 PSWIZB_BACK | PSWIZB_NEXT);
1648 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1649 LB_GETCURSEL, 0, 0);
1650 if (id == LB_ERR) {
1651 PropSheet_SetWizButtons(GetParent(hwnd),
1652 PSWIZB_BACK);
1653 SetDlgItemText(hwnd, IDC_PATH, "");
1654 SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1655 strcpy(python_dir, "");
1656 strcpy(pythondll, "");
1657 } else {
1658 char *pbuf;
1659 int result;
1660 InstalledVersionInfo *ivi;
1661 PropSheet_SetWizButtons(GetParent(hwnd),
1662 PSWIZB_BACK | PSWIZB_NEXT);
1663 /* Get the python directory */
Martin Panter6d57fe12016-09-17 03:26:16 +00001664 ivi = (InstalledVersionInfo *)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001665 SendDlgItemMessage(hwnd,
Martin Panter6d57fe12016-09-17 03:26:16 +00001666 IDC_VERSIONS_LIST,
1667 LB_GETITEMDATA,
1668 id,
1669 0);
1670 hkey_root = ivi->hkey;
1671 strcpy(python_dir, ivi->prefix);
1672 SetDlgItemText(hwnd, IDC_PATH, python_dir);
1673 /* retrieve the python version and pythondll to use */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001674 result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1675 LB_GETTEXTLEN, (WPARAM)id, 0);
1676 pbuf = (char *)malloc(result + 1);
1677 if (pbuf) {
1678 /* guess the name of the python-dll */
1679 SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1680 LB_GETTEXT, (WPARAM)id,
1681 (LPARAM)pbuf);
1682 result = sscanf(pbuf, "Python Version %d.%d",
1683 &py_major, &py_minor);
1684 if (result == 2) {
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001685#ifdef _DEBUG
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001686 wsprintf(pythondll, "python%d%d_d.dll",
1687 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001688#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001689 wsprintf(pythondll, "python%d%d.dll",
1690 py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001691#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001692 }
1693 free(pbuf);
1694 } else
1695 strcpy(pythondll, "");
1696 /* retrieve the scheme for this version */
1697 {
1698 char install_path[_MAX_PATH];
1699 SCHEME *scheme = GetScheme(py_major, py_minor);
1700 strcpy(install_path, python_dir);
1701 if (install_path[strlen(install_path)-1] != '\\')
1702 strcat(install_path, "\\");
1703 strcat(install_path, scheme[0].prefix);
1704 SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1705 }
1706 }
1707 }
1708 break;
1709 }
1710 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001711
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001712 case WM_NOTIFY:
1713 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001714
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001715 switch (lpnm->code) {
1716 int id;
1717 case PSN_SETACTIVE:
1718 id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1719 LB_GETCURSEL, 0, 0);
1720 if (id == LB_ERR)
1721 PropSheet_SetWizButtons(GetParent(hwnd),
1722 PSWIZB_BACK);
1723 else
1724 PropSheet_SetWizButtons(GetParent(hwnd),
1725 PSWIZB_BACK | PSWIZB_NEXT);
1726 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001727
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001728 case PSN_WIZNEXT:
1729 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001730
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001731 case PSN_WIZFINISH:
1732 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001733
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001734 case PSN_RESET:
1735 break;
1736
1737 default:
1738 break;
1739 }
1740 }
1741 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001742}
1743
1744static BOOL OpenLogfile(char *dir)
1745{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001746 char buffer[_MAX_PATH+1];
1747 time_t ltime;
1748 struct tm *now;
1749 long result;
1750 HKEY hKey, hSubkey;
1751 char subkey_name[256];
1752 static char KeyName[] =
1753 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1754 const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
1755 "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
1756 DWORD disposition;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001757
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001758 /* Use Create, as the Uninstall subkey may not exist under HKCU.
1759 Use CreateKeyEx, so we can specify a SAM specifying write access
1760 */
1761 result = RegCreateKeyEx(hkey_root,
1762 KeyName,
1763 0, /* reserved */
1764 NULL, /* class */
1765 0, /* options */
1766 KEY_CREATE_SUB_KEY, /* sam */
1767 NULL, /* security */
1768 &hKey, /* result key */
1769 NULL); /* disposition */
1770 if (result != ERROR_SUCCESS) {
1771 if (result == ERROR_ACCESS_DENIED) {
1772 /* This should no longer be able to happen - we have already
1773 checked if they have permissions in HKLM, and all users
1774 should have write access to HKCU.
1775 */
1776 MessageBox(GetFocus(),
1777 "You do not seem to have sufficient access rights\n"
1778 "on this machine to install this software",
1779 NULL,
1780 MB_OK | MB_ICONSTOP);
1781 return FALSE;
1782 } else {
1783 MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1784 }
1785 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001786
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001787 sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1788 logfile = fopen(buffer, "a");
Benjamin Peterson25c7d3f2014-11-27 20:39:02 -06001789 if (!logfile) {
1790 char error[1024];
1791
1792 sprintf(error, "Can't create \"%s\" (%s).\n\n"
1793 "Try to execute the installer as administrator.",
1794 buffer, strerror(errno));
1795 MessageBox(GetFocus(), error, NULL, MB_OK | MB_ICONSTOP);
1796 return FALSE;
1797 }
1798
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001799 time(&ltime);
1800 now = localtime(&ltime);
1801 strftime(buffer, sizeof(buffer),
1802 "*** Installation started %Y/%m/%d %H:%M ***\n",
1803 localtime(&ltime));
1804 fprintf(logfile, buffer);
1805 fprintf(logfile, "Source: %s\n", modulename);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001806
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001807 /* Root key must be first entry processed by uninstaller. */
1808 fprintf(logfile, "999 Root Key: %s\n", root_name);
Mark Hammondf9bfdd82004-07-02 23:53:16 +00001809
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001810 sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001811
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001812 result = RegCreateKeyEx(hKey, subkey_name,
1813 0, NULL, 0,
1814 KEY_WRITE,
1815 NULL,
1816 &hSubkey,
1817 &disposition);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001818
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001819 if (result != ERROR_SUCCESS)
1820 MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001821
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001822 RegCloseKey(hKey);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001823
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001824 if (disposition == REG_CREATED_NEW_KEY)
1825 fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001826
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001827 sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001828
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001829 result = RegSetValueEx(hSubkey, "DisplayName",
1830 0,
1831 REG_SZ,
1832 buffer,
1833 strlen(buffer)+1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001834
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001835 if (result != ERROR_SUCCESS)
1836 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001837
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001838 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1839 KeyName, subkey_name, "DisplayName", buffer);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001840
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001841 {
1842 FILE *fp;
1843 sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1844 fp = fopen(buffer, "wb");
1845 fwrite(arc_data, exe_size, 1, fp);
1846 fclose(fp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001847
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001848 sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1849 dir, meta_name, dir, meta_name);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001850
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001851 result = RegSetValueEx(hSubkey, "UninstallString",
1852 0,
1853 REG_SZ,
1854 buffer,
1855 strlen(buffer)+1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001856
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001857 if (result != ERROR_SUCCESS)
1858 MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1859
1860 fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1861 KeyName, subkey_name, "UninstallString", buffer);
1862 }
1863 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001864}
1865
1866static void CloseLogfile(void)
1867{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001868 char buffer[_MAX_PATH+1];
1869 time_t ltime;
1870 struct tm *now;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001871
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001872 time(&ltime);
1873 now = localtime(&ltime);
1874 strftime(buffer, sizeof(buffer),
1875 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1876 localtime(&ltime));
1877 fprintf(logfile, buffer);
1878 if (logfile)
1879 fclose(logfile);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001880}
1881
Steve Dower65e4cb12014-11-22 12:54:57 -08001882INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001883InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1884{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001885 LPNMHDR lpnm;
1886 char Buffer[4096];
1887 SCHEME *scheme;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001888
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001889 switch (msg) {
1890 case WM_INITDIALOG:
1891 if (hBitmap)
1892 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1893 IMAGE_BITMAP, (LPARAM)hBitmap);
1894 wsprintf(Buffer,
1895 "Click Next to begin the installation of %s. "
1896 "If you want to review or change any of your "
1897 " installation settings, click Back. "
1898 "Click Cancel to exit the wizard.",
1899 meta_name);
1900 SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1901 SetDlgItemText(hwnd, IDC_INFO, "Ready to install");
1902 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001903
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001904 case WM_NUMFILES:
1905 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1906 PumpMessages();
1907 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001908
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001909 case WM_NEXTFILE:
1910 SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1911 0);
1912 SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1913 PumpMessages();
1914 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001915
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001916 case WM_NOTIFY:
1917 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001918
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001919 switch (lpnm->code) {
1920 case PSN_SETACTIVE:
1921 PropSheet_SetWizButtons(GetParent(hwnd),
1922 PSWIZB_BACK | PSWIZB_NEXT);
1923 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001924
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001925 case PSN_WIZFINISH:
1926 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001927
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001928 case PSN_WIZNEXT:
1929 /* Handle a Next button click here */
1930 hDialog = hwnd;
1931 success = TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001932
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001933 /* Disable the buttons while we work. Sending CANCELTOCLOSE has
1934 the effect of disabling the cancel button, which is a) as we
1935 do everything synchronously we can't cancel, and b) the next
1936 step is 'finished', when it is too late to cancel anyway.
1937 The next step being 'Finished' means we also don't need to
1938 restore the button state back */
1939 PropSheet_SetWizButtons(GetParent(hwnd), 0);
1940 SendMessage(GetParent(hwnd), PSM_CANCELTOCLOSE, 0, 0);
1941 /* Make sure the installation directory name ends in a */
1942 /* backslash */
1943 if (python_dir[strlen(python_dir)-1] != '\\')
1944 strcat(python_dir, "\\");
1945 /* Strip the trailing backslash again */
1946 python_dir[strlen(python_dir)-1] = '\0';
1947
1948 CheckRootKey(hwnd);
1949
1950 if (!OpenLogfile(python_dir))
1951 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001952
1953/*
1954 * The scheme we have to use depends on the Python version...
1955 if sys.version < "2.2":
Serhiy Storchakad741a882015-06-11 00:06:39 +03001956 WINDOWS_SCHEME = {
1957 'purelib': '$base',
1958 'platlib': '$base',
1959 'headers': '$base/Include/$dist_name',
1960 'scripts': '$base/Scripts',
1961 'data' : '$base',
1962 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001963 else:
Serhiy Storchakad741a882015-06-11 00:06:39 +03001964 WINDOWS_SCHEME = {
1965 'purelib': '$base/Lib/site-packages',
1966 'platlib': '$base/Lib/site-packages',
1967 'headers': '$base/Include/$dist_name',
1968 'scripts': '$base/Scripts',
1969 'data' : '$base',
1970 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001971*/
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001972 scheme = GetScheme(py_major, py_minor);
1973 /* Run the pre-install script. */
1974 if (pre_install_script && *pre_install_script) {
1975 SetDlgItemText (hwnd, IDC_TITLE,
1976 "Running pre-installation script");
1977 run_simple_script(pre_install_script);
1978 }
1979 if (!success) {
1980 break;
1981 }
1982 /* Extract all files from the archive */
1983 SetDlgItemText(hwnd, IDC_TITLE, "Installing files...");
1984 if (!unzip_archive (scheme,
1985 python_dir, arc_data,
1986 arc_size, notify))
1987 set_failure_reason("Failed to unzip installation files");
1988 /* Compile the py-files */
1989 if (success && pyc_compile) {
1990 int errors;
1991 HINSTANCE hPython;
1992 SetDlgItemText(hwnd, IDC_TITLE,
1993 "Compiling files to .pyc...");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00001994
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001995 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
1996 hPython = LoadPythonDll(pythondll);
1997 if (hPython) {
1998 errors = compile_filelist(hPython, FALSE);
1999 FreeLibrary(hPython);
2000 }
2001 /* Compilation errors are intentionally ignored:
2002 * Python2.0 contains a bug which will result
2003 * in sys.path containing garbage under certain
2004 * circumstances, and an error message will only
2005 * confuse the user.
2006 */
2007 }
2008 if (success && pyo_compile) {
2009 int errors;
2010 HINSTANCE hPython;
2011 SetDlgItemText(hwnd, IDC_TITLE,
2012 "Compiling files to .pyo...");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002013
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002014 SetDlgItemText(hDialog, IDC_INFO, "Loading python...");
2015 hPython = LoadPythonDll(pythondll);
2016 if (hPython) {
2017 errors = compile_filelist(hPython, TRUE);
2018 FreeLibrary(hPython);
2019 }
2020 /* Errors ignored: see above */
2021 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002022
2023
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002024 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002025
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002026 case PSN_RESET:
2027 break;
2028
2029 default:
2030 break;
2031 }
2032 }
2033 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002034}
2035
2036
Steve Dower65e4cb12014-11-22 12:54:57 -08002037INT_PTR CALLBACK
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002038FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2039{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002040 LPNMHDR lpnm;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002041
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002042 switch (msg) {
2043 case WM_INITDIALOG:
2044 if (hBitmap)
2045 SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
2046 IMAGE_BITMAP, (LPARAM)hBitmap);
2047 if (!success)
2048 SetDlgItemText(hwnd, IDC_INFO, get_failure_reason());
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002049
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002050 /* async delay: will show the dialog box completely before
2051 the install_script is started */
2052 PostMessage(hwnd, WM_USER, 0, 0L);
2053 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002054
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002055 case WM_USER:
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002056
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002057 if (success && install_script && install_script[0]) {
2058 char fname[MAX_PATH];
2059 char *buffer;
2060 HCURSOR hCursor;
2061 int result;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002062
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002063 char *argv[3] = {NULL, "-install", NULL};
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002064
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002065 SetDlgItemText(hwnd, IDC_TITLE,
2066 "Please wait while running postinstall script...");
2067 strcpy(fname, python_dir);
2068 strcat(fname, "\\Scripts\\");
2069 strcat(fname, install_script);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002070
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002071 if (logfile)
2072 fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002073
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002074 hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002075
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002076 argv[0] = fname;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002077
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002078 result = run_installscript(fname, 2, argv, &buffer);
2079 if (0 != result) {
2080 fprintf(stderr, "*** run_installscript: internal error 0x%X ***\n", result);
2081 }
2082 if (buffer)
2083 SetDlgItemText(hwnd, IDC_INFO, buffer);
2084 SetDlgItemText(hwnd, IDC_TITLE,
2085 "Postinstall script finished.\n"
2086 "Click the Finish button to exit the Setup wizard.");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002087
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002088 free(buffer);
2089 SetCursor(hCursor);
2090 CloseLogfile();
2091 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002092
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002093 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002094
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002095 case WM_NOTIFY:
2096 lpnm = (LPNMHDR) lParam;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002097
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002098 switch (lpnm->code) {
2099 case PSN_SETACTIVE: /* Enable the Finish button */
2100 PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_FINISH);
2101 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002102
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002103 case PSN_WIZNEXT:
2104 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002105
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002106 case PSN_WIZFINISH:
2107 break;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002108
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002109 case PSN_RESET:
2110 break;
2111
2112 default:
2113 break;
2114 }
2115 }
2116 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002117}
2118
2119void RunWizard(HWND hwnd)
2120{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002121 PROPSHEETPAGE psp = {0};
2122 HPROPSHEETPAGE ahpsp[4] = {0};
2123 PROPSHEETHEADER psh = {0};
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002124
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002125 /* Display module information */
2126 psp.dwSize = sizeof(psp);
2127 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2128 psp.hInstance = GetModuleHandle (NULL);
2129 psp.lParam = 0;
2130 psp.pfnDlgProc = IntroDlgProc;
2131 psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002132
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002133 ahpsp[0] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002134
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002135 /* Select python version to use */
2136 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2137 psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTPYTHON);
2138 psp.pfnDlgProc = SelectPythonDlgProc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002139
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002140 ahpsp[1] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002141
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002142 /* Install the files */
2143 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2144 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFILES);
2145 psp.pfnDlgProc = InstallFilesDlgProc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002146
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002147 ahpsp[2] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002148
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002149 /* Show success or failure */
2150 psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER;
2151 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHED);
2152 psp.pfnDlgProc = FinishedDlgProc;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002153
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002154 ahpsp[3] = CreatePropertySheetPage(&psp);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002155
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002156 /* Create the property sheet */
2157 psh.dwSize = sizeof(psh);
2158 psh.hInstance = GetModuleHandle(NULL);
2159 psh.hwndParent = hwnd;
2160 psh.phpage = ahpsp;
2161 psh.dwFlags = PSH_WIZARD/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
2162 psh.pszbmWatermark = NULL;
2163 psh.pszbmHeader = NULL;
2164 psh.nStartPage = 0;
2165 psh.nPages = 4;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002166
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002167 PropertySheet(&psh);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002168}
2169
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002170// subtly different from HasLocalMachinePrivs(), in that after executing
2171// an 'elevated' process, we expect this to return TRUE - but there is no
2172// such implication for HasLocalMachinePrivs
2173BOOL MyIsUserAnAdmin()
2174{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002175 typedef BOOL (WINAPI *PFNIsUserAnAdmin)();
2176 static PFNIsUserAnAdmin pfnIsUserAnAdmin = NULL;
2177 HMODULE shell32;
2178 // This function isn't guaranteed to be available (and it can't hurt
2179 // to leave the library loaded)
2180 if (0 == (shell32=LoadLibrary("shell32.dll")))
2181 return FALSE;
2182 if (0 == (pfnIsUserAnAdmin=(PFNIsUserAnAdmin)GetProcAddress(shell32, "IsUserAnAdmin")))
2183 return FALSE;
2184 return (*pfnIsUserAnAdmin)();
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002185}
2186
2187// Some magic for Vista's UAC. If there is a target_version, and
2188// if that target version is installed in the registry under
2189// HKLM, and we are not current administrator, then
2190// re-execute ourselves requesting elevation.
2191// Split into 2 functions - "should we elevate" and "spawn elevated"
2192
2193// Returns TRUE if we should spawn an elevated child
2194BOOL NeedAutoUAC()
2195{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002196 HKEY hk;
2197 char key_name[80];
2198 // no Python version info == we can't know yet.
2199 if (target_version[0] == '\0')
2200 return FALSE;
2201 // see how python is current installed
2202 wsprintf(key_name,
2203 "Software\\Python\\PythonCore\\%s\\InstallPath",
2204 target_version);
2205 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2206 key_name, 0, KEY_READ, &hk))
2207 return FALSE;
2208 RegCloseKey(hk);
2209 // Python is installed in HKLM - we must elevate.
2210 return TRUE;
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002211}
2212
2213// Spawn ourself as an elevated application. On failure, a message is
2214// displayed to the user - but this app will always terminate, even
2215// on error.
2216void SpawnUAC()
2217{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002218 // interesting failure scenario that has been seen: initial executable
2219 // runs from a network drive - but once elevated, that network share
2220 // isn't seen, and ShellExecute fails with SE_ERR_ACCESSDENIED.
2221 int ret = (int)ShellExecute(0, "runas", modulename, "", NULL,
2222 SW_SHOWNORMAL);
2223 if (ret <= 32) {
2224 char msg[128];
2225 wsprintf(msg, "Failed to start elevated process (ShellExecute returned %d)", ret);
2226 MessageBox(0, msg, "Setup", MB_OK | MB_ICONERROR);
2227 }
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002228}
2229
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002230int DoInstall(void)
2231{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002232 char ini_buffer[4096];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002233
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002234 /* Read installation information */
2235 GetPrivateProfileString("Setup", "title", "", ini_buffer,
2236 sizeof(ini_buffer), ini_file);
2237 unescape(title, ini_buffer, sizeof(title));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002238
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002239 GetPrivateProfileString("Setup", "info", "", ini_buffer,
2240 sizeof(ini_buffer), ini_file);
2241 unescape(info, ini_buffer, sizeof(info));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002242
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002243 GetPrivateProfileString("Setup", "build_info", "", build_info,
2244 sizeof(build_info), ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002245
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002246 pyc_compile = GetPrivateProfileInt("Setup", "target_compile", 1,
2247 ini_file);
2248 pyo_compile = GetPrivateProfileInt("Setup", "target_optimize", 1,
2249 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002250
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002251 GetPrivateProfileString("Setup", "target_version", "",
2252 target_version, sizeof(target_version),
2253 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002254
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002255 GetPrivateProfileString("metadata", "name", "",
2256 meta_name, sizeof(meta_name),
2257 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002258
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002259 GetPrivateProfileString("Setup", "install_script", "",
2260 install_script, sizeof(install_script),
2261 ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002262
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002263 GetPrivateProfileString("Setup", "user_access_control", "",
2264 user_access_control, sizeof(user_access_control), ini_file);
Christian Heimes81ee3ef2008-05-04 22:42:01 +00002265
Steve Dower332334f2016-01-16 13:54:53 -08002266 strcat(target_version, REGISTRY_SUFFIX_6432);
2267
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002268 // See if we need to do the Vista UAC magic.
2269 if (strcmp(user_access_control, "force")==0) {
Steve Dower65e4cb12014-11-22 12:54:57 -08002270 if (!MyIsUserAnAdmin()) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002271 SpawnUAC();
2272 return 0;
2273 }
2274 // already admin - keep going
2275 } else if (strcmp(user_access_control, "auto")==0) {
2276 // Check if it looks like we need UAC control, based
2277 // on how Python itself was installed.
Steve Dower65e4cb12014-11-22 12:54:57 -08002278 if (!MyIsUserAnAdmin() && NeedAutoUAC()) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002279 SpawnUAC();
2280 return 0;
2281 }
2282 } else {
2283 // display a warning about unknown values - only the developer
2284 // of the extension will see it (until they fix it!)
2285 if (user_access_control[0] && strcmp(user_access_control, "none") != 0) {
2286 MessageBox(GetFocus(), "Bad user_access_control value", "oops", MB_OK);
2287 // nothing to do.
2288 }
2289 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002290
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002291 hwndMain = CreateBackground(title);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002292
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002293 RunWizard(hwndMain);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002294
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002295 /* Clean up */
2296 UnmapViewOfFile(arc_data);
2297 if (ini_file)
2298 DeleteFile(ini_file);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002299
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002300 if (hBitmap)
2301 DeleteObject(hBitmap);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002302
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002303 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002304}
2305
2306/*********************** uninstall section ******************************/
2307
2308static int compare(const void *p1, const void *p2)
2309{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002310 return strcmp(*(char **)p2, *(char **)p1);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002311}
2312
2313/*
2314 * Commit suicide (remove the uninstaller itself).
2315 *
2316 * Create a batch file to first remove the uninstaller
2317 * (will succeed after it has finished), then the batch file itself.
2318 *
2319 * This technique has been demonstrated by Jeff Richter,
2320 * MSJ 1/1996
2321 */
2322void remove_exe(void)
2323{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002324 char exename[_MAX_PATH];
2325 char batname[_MAX_PATH];
2326 FILE *fp;
2327 STARTUPINFO si;
2328 PROCESS_INFORMATION pi;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002329
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002330 GetModuleFileName(NULL, exename, sizeof(exename));
2331 sprintf(batname, "%s.bat", exename);
2332 fp = fopen(batname, "w");
2333 fprintf(fp, ":Repeat\n");
2334 fprintf(fp, "del \"%s\"\n", exename);
2335 fprintf(fp, "if exist \"%s\" goto Repeat\n", exename);
2336 fprintf(fp, "del \"%s\"\n", batname);
2337 fclose(fp);
2338
2339 ZeroMemory(&si, sizeof(si));
2340 si.cb = sizeof(si);
2341 si.dwFlags = STARTF_USESHOWWINDOW;
2342 si.wShowWindow = SW_HIDE;
2343 if (CreateProcess(NULL,
2344 batname,
2345 NULL,
2346 NULL,
2347 FALSE,
2348 CREATE_SUSPENDED | IDLE_PRIORITY_CLASS,
2349 NULL,
2350 "\\",
2351 &si,
2352 &pi)) {
2353 SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE);
2354 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
2355 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
2356 CloseHandle(pi.hProcess);
2357 ResumeThread(pi.hThread);
2358 CloseHandle(pi.hThread);
2359 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002360}
2361
2362void DeleteRegistryKey(char *string)
2363{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002364 char *keyname;
2365 char *subkeyname;
2366 char *delim;
2367 HKEY hKey;
2368 long result;
2369 char *line;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002370
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002371 line = strdup(string); /* so we can change it */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002372
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002373 keyname = strchr(line, '[');
2374 if (!keyname)
2375 return;
2376 ++keyname;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002377
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002378 subkeyname = strchr(keyname, ']');
2379 if (!subkeyname)
2380 return;
2381 *subkeyname++='\0';
2382 delim = strchr(subkeyname, '\n');
2383 if (delim)
2384 *delim = '\0';
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002385
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002386 result = RegOpenKeyEx(hkey_root,
2387 keyname,
2388 0,
2389 KEY_WRITE,
2390 &hKey);
2391
2392 if (result != ERROR_SUCCESS)
2393 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2394 else {
2395 result = RegDeleteKey(hKey, subkeyname);
2396 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
2397 MessageBox(GetFocus(), string, "Could not delete key", MB_OK);
2398 RegCloseKey(hKey);
2399 }
2400 free(line);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002401}
2402
2403void DeleteRegistryValue(char *string)
2404{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002405 char *keyname;
2406 char *valuename;
2407 char *value;
2408 HKEY hKey;
2409 long result;
2410 char *line;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002411
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002412 line = strdup(string); /* so we can change it */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002413
2414/* Format is 'Reg DB Value: [key]name=value' */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002415 keyname = strchr(line, '[');
2416 if (!keyname)
2417 return;
2418 ++keyname;
2419 valuename = strchr(keyname, ']');
2420 if (!valuename)
2421 return;
2422 *valuename++ = '\0';
2423 value = strchr(valuename, '=');
2424 if (!value)
2425 return;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002426
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002427 *value++ = '\0';
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002428
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002429 result = RegOpenKeyEx(hkey_root,
2430 keyname,
2431 0,
2432 KEY_WRITE,
2433 &hKey);
2434 if (result != ERROR_SUCCESS)
2435 MessageBox(GetFocus(), string, "Could not open key", MB_OK);
2436 else {
2437 result = RegDeleteValue(hKey, valuename);
2438 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
2439 MessageBox(GetFocus(), string, "Could not delete value", MB_OK);
2440 RegCloseKey(hKey);
2441 }
2442 free(line);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002443}
2444
2445BOOL MyDeleteFile(char *line)
2446{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002447 char *pathname = strchr(line, ':');
2448 if (!pathname)
2449 return FALSE;
2450 ++pathname;
2451 while (isspace(*pathname))
2452 ++pathname;
2453 return DeleteFile(pathname);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002454}
2455
2456BOOL MyRemoveDirectory(char *line)
2457{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002458 char *pathname = strchr(line, ':');
2459 if (!pathname)
2460 return FALSE;
2461 ++pathname;
2462 while (isspace(*pathname))
2463 ++pathname;
2464 return RemoveDirectory(pathname);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002465}
2466
2467BOOL Run_RemoveScript(char *line)
2468{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002469 char *dllname;
2470 char *scriptname;
2471 static char lastscript[MAX_PATH];
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002472
2473/* Format is 'Run Scripts: [pythondll]scriptname' */
2474/* XXX Currently, pythondll carries no path!!! */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002475 dllname = strchr(line, '[');
2476 if (!dllname)
2477 return FALSE;
2478 ++dllname;
2479 scriptname = strchr(dllname, ']');
2480 if (!scriptname)
2481 return FALSE;
2482 *scriptname++ = '\0';
2483 /* this function may be called more than one time with the same
2484 script, only run it one time */
2485 if (strcmp(lastscript, scriptname)) {
2486 char *argv[3] = {NULL, "-remove", NULL};
2487 char *buffer = NULL;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002488
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002489 argv[0] = scriptname;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002490
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002491 if (0 != run_installscript(scriptname, 2, argv, &buffer))
2492 fprintf(stderr, "*** Could not run installation script ***");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002493
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002494 if (buffer && buffer[0])
2495 MessageBox(GetFocus(), buffer, "uninstall-script", MB_OK);
2496 free(buffer);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002497
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002498 strcpy(lastscript, scriptname);
2499 }
2500 return TRUE;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002501}
2502
2503int DoUninstall(int argc, char **argv)
2504{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002505 FILE *logfile;
2506 char buffer[4096];
2507 int nLines = 0;
2508 int i;
2509 char *cp;
2510 int nFiles = 0;
2511 int nDirs = 0;
2512 int nErrors = 0;
2513 char **lines;
2514 int lines_buffer_size = 10;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002515
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002516 if (argc != 3) {
2517 MessageBox(NULL,
2518 "Wrong number of args",
2519 NULL,
2520 MB_OK);
2521 return 1; /* Error */
2522 }
2523 if (strcmp(argv[1], "-u")) {
2524 MessageBox(NULL,
2525 "2. arg is not -u",
2526 NULL,
2527 MB_OK);
2528 return 1; /* Error */
2529 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002530
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002531 logfile = fopen(argv[2], "r");
2532 if (!logfile) {
2533 MessageBox(NULL,
2534 "could not open logfile",
2535 NULL,
2536 MB_OK);
2537 return 1; /* Error */
2538 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002539
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002540 lines = (char **)malloc(sizeof(char *) * lines_buffer_size);
2541 if (!lines)
2542 return SystemError(0, "Out of memory");
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002543
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002544 /* Read the whole logfile, realloacting the buffer */
2545 while (fgets(buffer, sizeof(buffer), logfile)) {
2546 int len = strlen(buffer);
2547 /* remove trailing white space */
2548 while (isspace(buffer[len-1]))
2549 len -= 1;
2550 buffer[len] = '\0';
2551 lines[nLines++] = strdup(buffer);
2552 if (nLines >= lines_buffer_size) {
2553 lines_buffer_size += 10;
2554 lines = (char **)realloc(lines,
2555 sizeof(char *) * lines_buffer_size);
2556 if (!lines)
2557 return SystemError(0, "Out of memory");
2558 }
2559 }
2560 fclose(logfile);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002561
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002562 /* Sort all the lines, so that highest 3-digit codes are first */
2563 qsort(&lines[0], nLines, sizeof(char *),
2564 compare);
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002565
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002566 if (IDYES != MessageBox(NULL,
2567 "Are you sure you want to remove\n"
2568 "this package from your computer?",
2569 "Please confirm",
2570 MB_YESNO | MB_ICONQUESTION))
2571 return 0;
2572
2573 hkey_root = HKEY_LOCAL_MACHINE;
2574 cp = "";
2575 for (i = 0; i < nLines; ++i) {
2576 /* Ignore duplicate lines */
2577 if (strcmp(cp, lines[i])) {
2578 int ign;
2579 cp = lines[i];
2580 /* Parse the lines */
2581 if (2 == sscanf(cp, "%d Root Key: %s", &ign, &buffer)) {
2582 if (strcmp(buffer, "HKEY_CURRENT_USER")==0)
2583 hkey_root = HKEY_CURRENT_USER;
2584 else {
2585 // HKLM - check they have permissions.
2586 if (!HasLocalMachinePrivs()) {
2587 MessageBox(GetFocus(),
2588 "You do not seem to have sufficient access rights\n"
2589 "on this machine to uninstall this software",
2590 NULL,
2591 MB_OK | MB_ICONSTOP);
2592 return 1; /* Error */
2593 }
2594 }
2595 } else if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
2596 if (MyRemoveDirectory(cp))
2597 ++nDirs;
2598 else {
2599 int code = GetLastError();
2600 if (code != 2 && code != 3) { /* file or path not found */
2601 ++nErrors;
2602 }
2603 }
2604 } else if (2 == sscanf(cp, "%d File Copy: %s", &ign, &buffer)) {
2605 if (MyDeleteFile(cp))
2606 ++nFiles;
2607 else {
2608 int code = GetLastError();
2609 if (code != 2 && code != 3) { /* file or path not found */
2610 ++nErrors;
2611 }
2612 }
2613 } else if (2 == sscanf(cp, "%d File Overwrite: %s", &ign, &buffer)) {
2614 if (MyDeleteFile(cp))
2615 ++nFiles;
2616 else {
2617 int code = GetLastError();
2618 if (code != 2 && code != 3) { /* file or path not found */
2619 ++nErrors;
2620 }
2621 }
2622 } else if (2 == sscanf(cp, "%d Reg DB Key: %s", &ign, &buffer)) {
2623 DeleteRegistryKey(cp);
2624 } else if (2 == sscanf(cp, "%d Reg DB Value: %s", &ign, &buffer)) {
2625 DeleteRegistryValue(cp);
2626 } else if (2 == sscanf(cp, "%d Run Script: %s", &ign, &buffer)) {
2627 Run_RemoveScript(cp);
2628 }
2629 }
2630 }
2631
2632 if (DeleteFile(argv[2])) {
2633 ++nFiles;
2634 } else {
2635 ++nErrors;
2636 SystemError(GetLastError(), argv[2]);
2637 }
2638 if (nErrors)
2639 wsprintf(buffer,
2640 "%d files and %d directories removed\n"
2641 "%d files or directories could not be removed",
2642 nFiles, nDirs, nErrors);
2643 else
2644 wsprintf(buffer, "%d files and %d directories removed",
2645 nFiles, nDirs);
2646 MessageBox(NULL, buffer, "Uninstall Finished!",
2647 MB_OK | MB_ICONINFORMATION);
2648 remove_exe();
2649 return 0;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002650}
2651
2652int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002653 LPSTR lpszCmdLine, INT nCmdShow)
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002654{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002655 extern int __argc;
2656 extern char **__argv;
2657 char *basename;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002658
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002659 GetModuleFileName(NULL, modulename, sizeof(modulename));
2660 GetModuleFileNameW(NULL, wmodulename, sizeof(wmodulename)/sizeof(wmodulename[0]));
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002661
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002662 /* Map the executable file to memory */
2663 arc_data = MapExistingFile(modulename, &arc_size);
2664 if (!arc_data) {
2665 SystemError(GetLastError(), "Could not open archive");
2666 return 1;
2667 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002668
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002669 /* OK. So this program can act as installer (self-extracting
2670 * zip-file, or as uninstaller when started with '-u logfile'
2671 * command line flags.
2672 *
2673 * The installer is usually started without command line flags,
2674 * and the uninstaller is usually started with the '-u logfile'
2675 * flag. What to do if some innocent user double-clicks the
2676 * exe-file?
2677 * The following implements a defensive strategy...
2678 */
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002679
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002680 /* Try to extract the configuration data into a temporary file */
2681 if (ExtractInstallData(arc_data, arc_size, &exe_size,
2682 &ini_file, &pre_install_script))
2683 return DoInstall();
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002684
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002685 if (!ini_file && __argc > 1) {
2686 return DoUninstall(__argc, __argv);
2687 }
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002688
2689
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002690 basename = strrchr(modulename, '\\');
2691 if (basename)
2692 ++basename;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002693
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00002694 /* Last guess about the purpose of this program */
2695 if (basename && (0 == strncmp(basename, "Remove", 6)))
2696 SystemError(0, "This program is normally started by windows");
2697 else
2698 SystemError(0, "Setup program invalid or damaged");
2699 return 1;
Thomas Hellerbb4b7d22002-11-22 20:39:33 +00002700}