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