PageRenderTime 123ms CodeModel.GetById 22ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 0ms

/PC/bdist_wininst/install.c

http://unladen-swallow.googlecode.com/
C | 2660 lines | 2286 code | 176 blank | 198 comment | 109 complexity | ef7871ce251de8743397f0e4f4913198 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 69095 2009-01-29 12:31:51Z 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 */
 114FILE *logfile;
 115
 116char modulename[MAX_PATH];
 117
 118HWND hwndMain;
 119HWND hDialog;
 120
 121char *ini_file;			/* Full pathname of ini-file */
 122/* From ini-file */
 123char info[4096];		/* [Setup] info= */
 124char title[80];			/* [Setup] title=, contains package name
 125				   including version: "Distutils-1.0.1" */
 126char target_version[10];	/* [Setup] target_version=, required python
 127				   version or empty string */
 128char build_info[80];		/* [Setup] build_info=, distutils version
 129				   and build date */
 130
 131char meta_name[80];		/* package name without version like
 132				   'Distutils' */
 133char install_script[MAX_PATH];
 134char *pre_install_script; /* run before we install a single file */
 135
 136char user_access_control[10]; // one of 'auto', 'force', otherwise none.
 137
 138int py_major, py_minor;		/* Python version selected for installation */
 139
 140char *arc_data;			/* memory mapped archive */
 141DWORD arc_size;			/* number of bytes in archive */
 142int exe_size;			/* number of bytes for exe-file portion */
 143char python_dir[MAX_PATH];
 144char pythondll[MAX_PATH];
 145BOOL pyc_compile, pyo_compile;
 146/* Either HKLM or HKCU, depending on where Python itself is registered, and
 147   the permissions of the current user. */
 148HKEY hkey_root = (HKEY)-1;
 149
 150BOOL success;			/* Installation successfull? */
 151char *failure_reason = NULL;
 152
 153HANDLE hBitmap;
 154char *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
 163static 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! */
 167SCHEME 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
 176SCHEME 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
 185static 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
 222static struct tagFile {
 223	char *path;
 224	struct tagFile *next;
 225} *file_list = NULL;
 226
 227static void set_failure_reason(char *reason)
 228{
 229    if (failure_reason)
 230	free(failure_reason);
 231    failure_reason = strdup(reason);
 232    success = FALSE;
 233}
 234static char *get_failure_reason()
 235{
 236    if (!failure_reason)
 237	return "Installation failed.";
 238    return failure_reason;
 239}
 240
 241static 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
 250static 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
 300typedef 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 */
 307static 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
 338typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
 339
 340struct PyMethodDef {
 341	char	*ml_name;
 342	PyCFunction  ml_meth;
 343	int		 ml_flags;
 344	char	*ml_doc;
 345};
 346typedef 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.
 354void *(*g_Py_BuildValue)(char *, ...);
 355int (*g_PyArg_ParseTuple)(PyObject *, char *, ...);
 356PyObject * (*g_PyLong_FromVoidPtr)(void *);
 357
 358PyObject *g_PyExc_ValueError;
 359PyObject *g_PyExc_OSError;
 360
 361PyObject *(*g_PyErr_Format)(PyObject *, char *, ...);
 362
 363#define DEF_CSIDL(name) { name, #name }
 364
 365struct {
 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
 408static 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
 417static 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
 426static 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
 476static 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
 595static 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
 606static PyObject *GetRootHKey(PyObject *self)
 607{
 608	return g_PyLong_FromVoidPtr(hkey_root);
 609}
 610
 611#define METH_VARARGS 0x0001
 612#define METH_NOARGS   0x0004
 613typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
 614
 615PyMethodDef 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
 624static 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
 651static 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
 696static int
 697do_run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
 698{
 699	int fh, result;
 700	DECLPROC(hPython, void, Py_Initialize, (void));
 701	DECLPROC(hPython, int, PySys_SetArgv, (int, char **));
 702	DECLPROC(hPython, int, PyRun_SimpleString, (char *));
 703	DECLPROC(hPython, void, Py_Finalize, (void));
 704	DECLPROC(hPython, PyObject *, Py_BuildValue, (char *, ...));
 705	DECLPROC(hPython, PyObject *, PyCFunction_New,
 706		 (PyMethodDef *, PyObject *));
 707	DECLPROC(hPython, int, PyArg_ParseTuple, (PyObject *, char *, ...));
 708	DECLPROC(hPython, PyObject *, PyErr_Format, (PyObject *, char *));
 709
 710	if (!Py_Initialize || !PySys_SetArgv
 711	    || !PyRun_SimpleString || !Py_Finalize)
 712		return 1;
 713	
 714	if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
 715		return 1;
 716
 717	if (!PyCFunction_New || !PyArg_ParseTuple || !PyErr_Format)
 718		return 1;
 719
 720	if (pathname == NULL || pathname[0] == '\0')
 721		return 2;
 722
 723	fh = open(pathname, _O_RDONLY);
 724	if (-1 == fh) {
 725		fprintf(stderr, "Could not open postinstall-script %s\n",
 726			pathname);
 727		return 3;
 728	}
 729
 730	SetDlgItemText(hDialog, IDC_INFO, "Running Script...");
 731
 732	Py_Initialize();
 733
 734	prepare_script_environment(hPython);
 735	PySys_SetArgv(argc, argv);
 736	result = 3;
 737	{
 738		struct _stat statbuf;
 739		if(0 == _fstat(fh, &statbuf)) {
 740			char *script = alloca(statbuf.st_size + 5);
 741			int n = read(fh, script, statbuf.st_size);
 742			if (n > 0) {
 743				script[n] = '\n';
 744				script[n+1] = 0;
 745				result = PyRun_SimpleString(script);
 746			}
 747		}
 748	}
 749	Py_Finalize();
 750
 751	close(fh);
 752	return result;
 753}
 754
 755static int
 756run_installscript(char *pathname, int argc, char **argv, char **pOutput)
 757{
 758	HINSTANCE hPython;
 759	int result = 1;
 760	int out_buf_size;
 761	HANDLE redirected, old_stderr, old_stdout;
 762	char *tempname;
 763
 764	*pOutput = NULL;
 765
 766	tempname = tempnam(NULL, NULL);
 767	// We use a static CRT while the Python version we load uses
 768	// the CRT from one of various possibile DLLs.  As a result we
 769	// need to redirect the standard handles using the API rather
 770	// than the CRT.
 771	redirected = CreateFile(
 772					tempname,
 773					GENERIC_WRITE | GENERIC_READ,
 774					FILE_SHARE_READ,
 775					NULL,
 776					CREATE_ALWAYS,
 777					FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
 778					NULL);
 779	old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
 780	old_stderr = GetStdHandle(STD_ERROR_HANDLE);
 781	SetStdHandle(STD_OUTPUT_HANDLE, redirected);
 782	SetStdHandle(STD_ERROR_HANDLE, redirected);
 783
 784	hPython = LoadPythonDll(pythondll);
 785	if (hPython) {
 786		result = do_run_installscript(hPython, pathname, argc, argv);
 787		FreeLibrary(hPython);
 788	} else {
 789		fprintf(stderr, "*** Could not load Python ***");
 790	}
 791	SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
 792	SetStdHandle(STD_ERROR_HANDLE, old_stderr);
 793	out_buf_size = min(GetFileSize(redirected, NULL), 4096);
 794	*pOutput = malloc(out_buf_size+1);
 795	if (*pOutput) {
 796		DWORD nread = 0;
 797		SetFilePointer(redirected, 0, 0, FILE_BEGIN);
 798		ReadFile(redirected, *pOutput, out_buf_size, &nread, NULL);
 799		(*pOutput)[nread] = '\0';
 800	}
 801	CloseHandle(redirected);
 802	DeleteFile(tempname);
 803	return result;
 804}
 805
 806static int do_run_simple_script(HINSTANCE hPython, char *script)
 807{
 808	int rc;
 809	DECLPROC(hPython, void, Py_Initialize, (void));
 810	DECLPROC(hPython, void, Py_SetProgramName, (char *));
 811	DECLPROC(hPython, void, Py_Finalize, (void));
 812	DECLPROC(hPython, int, PyRun_SimpleString, (char *));
 813	DECLPROC(hPython, void, PyErr_Print, (void));
 814
 815	if (!Py_Initialize || !Py_SetProgramName || !Py_Finalize || 
 816	    !PyRun_SimpleString || !PyErr_Print)
 817		return -1;
 818
 819	Py_SetProgramName(modulename);
 820	Py_Initialize();
 821	prepare_script_environment(hPython);
 822	rc = PyRun_SimpleString(script);
 823	if (rc)
 824		PyErr_Print();
 825	Py_Finalize();
 826	return rc;
 827}
 828
 829static int run_simple_script(char *script)
 830{
 831	int rc;
 832	HINSTANCE hPython;
 833	char *tempname = tempnam(NULL, NULL);
 834	// Redirect output using win32 API - see comments above...
 835	HANDLE redirected = CreateFile(
 836					tempname,
 837					GENERIC_WRITE | GENERIC_READ,
 838					FILE_SHARE_READ,
 839					NULL,
 840					CREATE_ALWAYS,
 841					FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
 842					NULL);
 843	HANDLE old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
 844	HANDLE old_stderr = GetStdHandle(STD_ERROR_HANDLE);
 845	SetStdHandle(STD_OUTPUT_HANDLE, redirected);
 846	SetStdHandle(STD_ERROR_HANDLE, redirected);
 847
 848	hPython = LoadPythonDll(pythondll);
 849	if (!hPython) {
 850		char reason[128];
 851		wsprintf(reason, "Can't load Python for pre-install script (%d)", GetLastError());
 852		set_failure_reason(reason);
 853		return -1;
 854	}
 855	rc = do_run_simple_script(hPython, script);
 856	FreeLibrary(hPython);
 857	SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
 858	SetStdHandle(STD_ERROR_HANDLE, old_stderr);
 859	/* We only care about the output when we fail.  If the script works
 860	   OK, then we discard it
 861	*/
 862	if (rc) {
 863		int err_buf_size;
 864		char *err_buf;
 865		const char *prefix = "Running the pre-installation script failed\r\n";
 866		int prefix_len = strlen(prefix);
 867		err_buf_size = GetFileSize(redirected, NULL);
 868		if (err_buf_size==INVALID_FILE_SIZE) // an error - let's try anyway...
 869			err_buf_size = 4096;
 870		err_buf = malloc(prefix_len + err_buf_size + 1);
 871		if (err_buf) {
 872			DWORD n = 0;
 873			strcpy(err_buf, prefix);
 874			SetFilePointer(redirected, 0, 0, FILE_BEGIN);
 875			ReadFile(redirected, err_buf+prefix_len, err_buf_size, &n, NULL);
 876			err_buf[prefix_len+n] = '\0';
 877			set_failure_reason(err_buf);
 878			free(err_buf);
 879		} else {
 880			set_failure_reason("Out of memory!");
 881		}
 882	}
 883	CloseHandle(redirected);
 884	DeleteFile(tempname);
 885	return rc;
 886}
 887
 888
 889static BOOL SystemError(int error, char *msg)
 890{
 891	char Buffer[1024];
 892	int n;
 893
 894	if (error) {
 895		LPVOID lpMsgBuf;
 896		FormatMessage( 
 897			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
 898			FORMAT_MESSAGE_FROM_SYSTEM,
 899			NULL,
 900			error,
 901			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 902			(LPSTR)&lpMsgBuf,
 903			0,
 904			NULL 
 905			);
 906		strncpy(Buffer, lpMsgBuf, sizeof(Buffer));
 907		LocalFree(lpMsgBuf);
 908	} else
 909		Buffer[0] = '\0';
 910	n = lstrlen(Buffer);
 911	_snprintf(Buffer+n, sizeof(Buffer)-n, msg);
 912	MessageBox(hwndMain, Buffer, "Runtime Error", MB_OK | MB_ICONSTOP);
 913	return FALSE;
 914}
 915
 916static BOOL notify (int code, char *fmt, ...)
 917{
 918	char Buffer[1024];
 919	va_list marker;
 920	BOOL result = TRUE;
 921	int a, b;
 922	char *cp;
 923
 924	va_start(marker, fmt);
 925	_vsnprintf(Buffer, sizeof(Buffer), fmt, marker);
 926
 927	switch (code) {
 928/* Questions */
 929	case CAN_OVERWRITE:
 930		break;
 931
 932/* Information notification */
 933	case DIR_CREATED:
 934		if (logfile)
 935			fprintf(logfile, "100 Made Dir: %s\n", fmt);
 936		break;
 937
 938	case FILE_CREATED:
 939		if (logfile)
 940			fprintf(logfile, "200 File Copy: %s\n", fmt);
 941		goto add_to_filelist_label;
 942		break;
 943
 944	case FILE_OVERWRITTEN:
 945		if (logfile)
 946			fprintf(logfile, "200 File Overwrite: %s\n", fmt);
 947	  add_to_filelist_label:
 948		if ((cp = strrchr(fmt, '.')) && (0 == strcmp (cp, ".py")))
 949			add_to_filelist(fmt);
 950		break;
 951
 952/* Error Messages */
 953	case ZLIB_ERROR:
 954		MessageBox(GetFocus(), Buffer, "Error",
 955			    MB_OK | MB_ICONWARNING);
 956		break;
 957
 958	case SYSTEM_ERROR:
 959		SystemError(GetLastError(), Buffer);
 960		break;
 961
 962	case NUM_FILES:
 963		a = va_arg(marker, int);
 964		b = va_arg(marker, int);
 965		SendMessage(hDialog, WM_NUMFILES, 0, MAKELPARAM(0, a));
 966		SendMessage(hDialog, WM_NEXTFILE, b,(LPARAM)fmt);
 967	}
 968	va_end(marker);
 969    
 970	return result;
 971}
 972
 973static char *MapExistingFile(char *pathname, DWORD *psize)
 974{
 975	HANDLE hFile, hFileMapping;
 976	DWORD nSizeLow, nSizeHigh;
 977	char *data;
 978
 979	hFile = CreateFile(pathname,
 980			    GENERIC_READ, FILE_SHARE_READ, NULL,
 981			    OPEN_EXISTING,
 982			    FILE_ATTRIBUTE_NORMAL, NULL);
 983	if (hFile == INVALID_HANDLE_VALUE)
 984		return NULL;
 985	nSizeLow = GetFileSize(hFile, &nSizeHigh);
 986	hFileMapping = CreateFileMapping(hFile,
 987					  NULL, PAGE_READONLY, 0, 0, NULL);
 988	CloseHandle(hFile);
 989
 990	if (hFileMapping == INVALID_HANDLE_VALUE)
 991		return NULL;
 992    
 993	data = MapViewOfFile(hFileMapping,
 994			      FILE_MAP_READ, 0, 0, 0);
 995
 996	CloseHandle(hFileMapping);
 997	*psize = nSizeLow;
 998	return data;
 999}
1000
1001
1002static void create_bitmap(HWND hwnd)
1003{
1004	BITMAPFILEHEADER *bfh;
1005	BITMAPINFO *bi;
1006	HDC hdc;
1007
1008	if (!bitmap_bytes)
1009		return;
1010
1011	if (hBitmap)
1012		return;
1013
1014	hdc = GetDC(hwnd);
1015
1016	bfh = (BITMAPFILEHEADER *)bitmap_bytes;
1017	bi = (BITMAPINFO *)(bitmap_bytes + sizeof(BITMAPFILEHEADER));
1018
1019	hBitmap = CreateDIBitmap(hdc,
1020				 &bi->bmiHeader,
1021				 CBM_INIT,
1022				 bitmap_bytes + bfh->bfOffBits,
1023				 bi,
1024				 DIB_RGB_COLORS);
1025	ReleaseDC(hwnd, hdc);
1026}
1027
1028/* Extract everything we need to begin the installation.  Currently this
1029   is the INI filename with install data, and the raw pre-install script
1030*/
1031static BOOL ExtractInstallData(char *data, DWORD size, int *pexe_size,
1032			       char **out_ini_file, char **out_preinstall_script)
1033{
1034	/* read the end of central directory record */
1035	struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
1036						       (struct eof_cdir)];
1037    
1038	int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
1039		pe->ofsCDir;
1040
1041	int ofs = arc_start - sizeof (struct meta_data_hdr);
1042
1043	/* read meta_data info */
1044	struct meta_data_hdr *pmd = (struct meta_data_hdr *)&data[ofs];
1045	char *src, *dst;
1046	char *ini_file;
1047	char tempdir[MAX_PATH];
1048
1049	/* ensure that if we fail, we don't have garbage out pointers */
1050	*out_ini_file = *out_preinstall_script = NULL;
1051
1052	if (pe->tag != 0x06054b50) {
1053		return FALSE;
1054	}
1055
1056	if (pmd->tag != 0x1234567B) {
1057		return SystemError(0,
1058			   "Invalid cfgdata magic number (see bdist_wininst.py)");
1059	}
1060	if (ofs < 0) {
1061		return FALSE;
1062	}
1063
1064	if (pmd->bitmap_size) {
1065		/* Store pointer to bitmap bytes */
1066		bitmap_bytes = (char *)pmd - pmd->uncomp_size - pmd->bitmap_size;
1067	}
1068
1069	*pexe_size = ofs - pmd->uncomp_size - pmd->bitmap_size;
1070
1071	src = ((char *)pmd) - pmd->uncomp_size;
1072	ini_file = malloc(MAX_PATH); /* will be returned, so do not free it */
1073	if (!ini_file)
1074		return FALSE;
1075	if (!GetTempPath(sizeof(tempdir), tempdir)
1076	    || !GetTempFileName(tempdir, "~du", 0, ini_file)) {
1077		SystemError(GetLastError(),
1078			     "Could not create temporary file");
1079		return FALSE;
1080	}
1081    
1082	dst = map_new_file(CREATE_ALWAYS, ini_file, NULL, pmd->uncomp_size,
1083			    0, 0, NULL/*notify*/);
1084	if (!dst)
1085		return FALSE;
1086	/* Up to the first \0 is the INI file data. */
1087	strncpy(dst, src, pmd->uncomp_size);
1088	src += strlen(dst) + 1;
1089	/* Up to next \0 is the pre-install script */
1090	*out_preinstall_script = strdup(src);
1091	*out_ini_file = ini_file;
1092	UnmapViewOfFile(dst);
1093	return TRUE;
1094}
1095
1096static void PumpMessages(void)
1097{
1098	MSG msg;
1099	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1100		TranslateMessage(&msg);
1101		DispatchMessage(&msg);
1102	}
1103}
1104
1105LRESULT CALLBACK
1106WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1107{
1108	HDC hdc;
1109	HFONT hFont;
1110	int h;
1111	PAINTSTRUCT ps;
1112	switch (msg) {
1113	case WM_PAINT:
1114		hdc = BeginPaint(hwnd, &ps);
1115		h = GetSystemMetrics(SM_CYSCREEN) / 10;
1116		hFont = CreateFont(h, 0, 0, 0, 700, TRUE,
1117				    0, 0, 0, 0, 0, 0, 0, "Times Roman");
1118		hFont = SelectObject(hdc, hFont);
1119		SetBkMode(hdc, TRANSPARENT);
1120		TextOut(hdc, 15, 15, title, strlen(title));
1121		SetTextColor(hdc, RGB(255, 255, 255));
1122		TextOut(hdc, 10, 10, title, strlen(title));
1123		DeleteObject(SelectObject(hdc, hFont));
1124		EndPaint(hwnd, &ps);
1125		return 0;
1126	}
1127	return DefWindowProc(hwnd, msg, wParam, lParam);
1128}
1129
1130static HWND CreateBackground(char *title)
1131{
1132	WNDCLASS wc;
1133	HWND hwnd;
1134	char buffer[4096];
1135
1136	wc.style = CS_VREDRAW | CS_HREDRAW;
1137	wc.lpfnWndProc = WindowProc;
1138	wc.cbWndExtra = 0;
1139	wc.cbClsExtra = 0;
1140	wc.hInstance = GetModuleHandle(NULL);
1141	wc.hIcon = NULL;
1142	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1143	wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 128));
1144	wc.lpszMenuName = NULL;
1145	wc.lpszClassName = "SetupWindowClass";
1146
1147	if (!RegisterClass(&wc))
1148		MessageBox(hwndMain,
1149			    "Could not register window class",
1150			    "Setup.exe", MB_OK);
1151
1152	wsprintf(buffer, "Setup %s", title);
1153	hwnd = CreateWindow("SetupWindowClass",
1154			     buffer,
1155			     0,
1156			     0, 0,
1157			     GetSystemMetrics(SM_CXFULLSCREEN),
1158			     GetSystemMetrics(SM_CYFULLSCREEN),
1159			     NULL,
1160			     NULL,
1161			     GetModuleHandle(NULL),
1162			     NULL);
1163	ShowWindow(hwnd, SW_SHOWMAXIMIZED);
1164	UpdateWindow(hwnd);
1165	return hwnd;
1166}
1167
1168/*
1169 * Center a window on the screen
1170 */
1171static void CenterWindow(HWND hwnd)
1172{
1173	RECT rc;
1174	int w, h;
1175
1176	GetWindowRect(hwnd, &rc);
1177	w = GetSystemMetrics(SM_CXSCREEN);
1178	h = GetSystemMetrics(SM_CYSCREEN);
1179	MoveWindow(hwnd,
1180		   (w - (rc.right-rc.left))/2,
1181		   (h - (rc.bottom-rc.top))/2,
1182		    rc.right-rc.left, rc.bottom-rc.top, FALSE);
1183}
1184
1185#include <prsht.h>
1186
1187BOOL CALLBACK
1188IntroDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1189{
1190	LPNMHDR lpnm;
1191	char Buffer[4096];
1192
1193	switch (msg) {
1194	case WM_INITDIALOG:
1195		create_bitmap(hwnd);
1196		if(hBitmap)
1197			SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1198					   IMAGE_BITMAP, (LPARAM)hBitmap);
1199		CenterWindow(GetParent(hwnd));
1200		wsprintf(Buffer,
1201			  "This Wizard will install %s on your computer. "
1202			  "Click Next to continue "
1203			  "or Cancel to exit the Setup Wizard.",
1204			  meta_name);
1205		SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1206		SetDlgItemText(hwnd, IDC_INTRO_TEXT, info);
1207		SetDlgItemText(hwnd, IDC_BUILD_INFO, build_info);
1208		return FALSE;
1209
1210	case WM_NOTIFY:
1211		lpnm = (LPNMHDR) lParam;
1212
1213		switch (lpnm->code) {
1214		case PSN_SETACTIVE:
1215			PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_NEXT);
1216			break;
1217
1218		case PSN_WIZNEXT:
1219			break;
1220
1221		case PSN_RESET:
1222			break;
1223		
1224		default:
1225			break;
1226		}
1227	}
1228	return FALSE;
1229}
1230
1231#ifdef USE_OTHER_PYTHON_VERSIONS
1232/* These are really private variables used to communicate
1233 * between StatusRoutine and CheckPythonExe
1234 */
1235char bound_image_dll[_MAX_PATH];
1236int bound_image_major;
1237int bound_image_minor;
1238
1239static BOOL __stdcall StatusRoutine(IMAGEHLP_STATUS_REASON reason,
1240				    PSTR ImageName,
1241				    PSTR DllName,
1242				    ULONG Va,
1243				    ULONG Parameter)
1244{
1245	char fname[_MAX_PATH];
1246	int int_version;
1247
1248	switch(reason) {
1249	case BindOutOfMemory:
1250	case BindRvaToVaFailed:
1251	case BindNoRoomInImage:
1252	case BindImportProcedureFailed:
1253		break;
1254
1255	case BindImportProcedure:
1256	case BindForwarder:
1257	case BindForwarderNOT:
1258	case BindImageModified:
1259	case BindExpandFileHeaders:
1260	case BindImageComplete:
1261	case BindSymbolsNotUpdated:
1262	case BindMismatchedSymbols:
1263	case BindImportModuleFailed:
1264		break;
1265
1266	case BindImportModule:
1267		if (1 == sscanf(DllName, "python%d", &int_version)) {
1268			SearchPath(NULL, DllName, NULL, sizeof(fname),
1269				   fname, NULL);
1270			strcpy(bound_image_dll, fname);
1271			bound_image_major = int_version / 10;
1272			bound_image_minor = int_version % 10;
1273			OutputDebugString("BOUND ");
1274			OutputDebugString(fname);
1275			OutputDebugString("\n");
1276		}
1277		break;
1278	}
1279	return TRUE;
1280}
1281
1282/*
1283 */
1284static LPSTR get_sys_prefix(LPSTR exe, LPSTR dll)
1285{
1286	void (__cdecl * Py_Initialize)(void);
1287	void (__cdecl * Py_SetProgramName)(char *);
1288	void (__cdecl * Py_Finalize)(void);
1289	void* (__cdecl * PySys_GetObject)(char *);
1290	void (__cdecl * PySys_SetArgv)(int, char **);
1291	char* (__cdecl * Py_GetPrefix)(void);
1292	char* (__cdecl * Py_GetPath)(void);
1293	HINSTANCE hPython;
1294	LPSTR prefix = NULL;
1295	int (__cdecl * PyRun_SimpleString)(char *);
1296
1297	{
1298		char Buffer[256];
1299		wsprintf(Buffer, "PYTHONHOME=%s", exe);
1300		*strrchr(Buffer, '\\') = '\0';
1301//	MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1302		_putenv(Buffer);
1303		_putenv("PYTHONPATH=");
1304	}
1305
1306	hPython = LoadLibrary(dll);
1307	if (!hPython)
1308		return NULL;
1309	Py_Initialize = (void (*)(void))GetProcAddress
1310		(hPython,"Py_Initialize");
1311
1312	PySys_SetArgv = (void (*)(int, char **))GetProcAddress
1313		(hPython,"PySys_SetArgv");
1314
1315	PyRun_SimpleString = (int (*)(char *))GetProcAddress
1316		(hPython,"PyRun_SimpleString");
1317
1318	Py_SetProgramName = (void (*)(char *))GetProcAddress
1319		(hPython,"Py_SetProgramName");
1320
1321	PySys_GetObject = (void* (*)(char *))GetProcAddress
1322		(hPython,"PySys_GetObject");
1323
1324	Py_GetPrefix = (char * (*)(void))GetProcAddress
1325		(hPython,"Py_GetPrefix");
1326
1327	Py_GetPath = (char * (*)(void))GetProcAddress
1328		(hPython,"Py_GetPath");
1329
1330	Py_Finalize = (void (*)(void))GetProcAddress(hPython,
1331						      "Py_Finalize");
1332	Py_SetProgramName(exe);
1333	Py_Initialize();
1334	PySys_SetArgv(1, &exe);
1335
1336	MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK);
1337	MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK);
1338
1339	Py_Finalize();
1340	FreeLibrary(hPython);
1341
1342	return prefix;
1343}
1344
1345static BOOL
1346CheckPythonExe(LPSTR pathname, LPSTR version, int *pmajor, int *pminor)
1347{
1348	bound_image_dll[0] = '\0';
1349	if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
1350			 pathname,
1351			 NULL,
1352			 NULL,
1353			 StatusRoutine))
1354		return SystemError(0, "Could not bind image");
1355	if (bound_image_dll[0] == '\0')
1356		return SystemError(0, "Does not seem to be a python executable");
1357	*pmajor = bound_image_major;
1358	*pminor = bound_image_minor;
1359	if (version && *version) {
1360		char core_version[12];
1361		wsprintf(core_version, "%d.%d", bound_image_major, bound_image_minor);
1362		if (strcmp(version, core_version))
1363			return SystemError(0, "Wrong Python version");
1364	}
1365	get_sys_prefix(pathname, bound_image_dll);
1366	return TRUE;
1367}
1368
1369/*
1370 * Browse for other python versions. Insert it into the listbox specified
1371 * by hwnd. version, if not NULL or empty, is the version required.
1372 */
1373static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
1374{
1375	char vers_name[_MAX_PATH + 80];
1376	DWORD itemindex;
1377	OPENFILENAME of;
1378	char pathname[_MAX_PATH];
1379	DWORD result;
1380
1381	strcpy(pathname, "python.exe");
1382
1383	memset(&of, 0, sizeof(of));
1384	of.lStructSize = sizeof(OPENFILENAME);
1385	of.hwndOwner = GetParent(hwnd);
1386	of.hInstance = NULL;
1387	of.lpstrFilter = "python.exe\0python.exe\0";
1388	of.lpstrCustomFilter = NULL;
1389	of.nMaxCustFilter = 0;
1390	of.nFilterIndex = 1;
1391	of.lpstrFile = pathname;
1392	of.nMaxFile = sizeof(pathname);
1393	of.lpstrFileTitle = NULL;
1394	of.nMaxFileTitle = 0;
1395	of.lpstrInitialDir = NULL;
1396	of.lpstrTitle = "Python executable";
1397	of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
1398	of.lpstrDefExt = "exe";
1399
1400	result = GetOpenFileName(&of);
1401	if (result) {
1402		int major, minor;
1403		if (!CheckPythonExe(pathname, version, &major, &minor)) {
1404			return FALSE;
1405		}
1406		*strrchr(pathname, '\\') = '\0';
1407		wsprintf(vers_name, "Python Version %d.%d in %s",
1408			  major, minor, pathname);
1409		itemindex = SendMessage(hwnd, LB_INSERTSTRING, -1,
1410					(LPARAM)(LPSTR)vers_name);
1411		SendMessage(hwnd, LB_SETCURSEL, itemindex, 0);
1412		SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1413			    (LPARAM)(LPSTR)strdup(pathname));
1414		return TRUE;
1415	}
1416	return FALSE;
1417}
1418#endif /* USE_OTHER_PYTHON_VERSIONS */
1419
1420typedef struct _InstalledVersionInfo {
1421    char prefix[MAX_PATH+1]; // sys.prefix directory.
1422    HKEY hkey; // Is this Python in HKCU or HKLM?
1423} InstalledVersionInfo;
1424
1425
1426/*
1427 * Fill the listbox specified by hwnd with all python versions found
1428 * in the registry. version, if not NULL or empty, is the version
1429 * required.
1430 */
1431static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
1432{
1433	DWORD index = 0;
1434	char core_version[80];
1435	HKEY hKey;
1436	BOOL result = TRUE;
1437	DWORD bufsize;
1438
1439	if (ERROR_SUCCESS != RegOpenKeyEx(hkRoot,
1440					   "Software\\Python\\PythonCore",
1441					   0,	KEY_READ, &hKey))
1442		return FALSE;
1443	bufsize = sizeof(core_version);
1444	while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
1445					      core_version, &bufsize, NULL,
1446					      NULL, NULL, NULL)) {
1447		char subkey_name[80], vers_name[80];
1448		int itemindex;
1449		DWORD value_size;
1450		HKEY hk;
1451
1452		bufsize = sizeof(core_version);
1453		++index;
1454		if (version && *version && strcmp(version, core_version))
1455			continue;
1456
1457		wsprintf(vers_name, "Python Version %s (found in registry)",
1458			  core_version);
1459		wsprintf(subkey_name,
1460			  "Software\\Python\\PythonCore\\%s\\InstallPath",
1461			  core_version);
1462		if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
1463			InstalledVersionInfo *ivi = 
1464			      (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
1465			value_size = sizeof(ivi->prefix);
1466			if (ivi && 
1467			    ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
1468			                                     ivi->prefix, &value_size)) {
1469				itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
1470				                        (LPARAM)(LPSTR)vers_name);
1471				ivi->hkey = hkRoot;
1472				SendMessage(hwnd, LB_SETITEMDATA, itemindex,
1473				            (LPARAM)(LPSTR)ivi);
1474			}
1475			RegCloseKey(hk);
1476		}
1477	}
1478	RegCloseKey(hKey);
1479	return result;
1480}
1481
1482/* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1483BOOL HasLocalMachinePrivs()
1484{
1485		HKEY hKey;
1486		DWORD result;
1487		static char KeyName[] = 
1488			"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1489
1490		result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1491					  KeyName,
1492					  0,
1493					  KEY_CREATE_SUB_KEY,
1494					  &hKey);
1495		if (result==0)
1496			RegCloseKey(hKey);
1497		return result==0;
1498}
1499
1500// Check the root registry key to use - either HKLM or HKCU.
1501// If Python is installed in HKCU, then our extension also must be installed
1502// in HKCU - as Python won't be available for other users, we shouldn't either
1503// (and will fail if we are!)
1504// If Python is installed in HKLM, then we will also prefer to use HKLM, but
1505// this may not be possible - so we silently fall back to HKCU.
1506//
1507// We assume hkey_root is already set to where Python itself is installed.
1508void CheckRootKey(HWND hwnd)
1509{
1510	if (hkey_root==HKEY_CURRENT_USER) {
1511		; // as above, always install ourself in HKCU too.
1512	} else if (hkey_root==HKEY_LOCAL_MACHINE) {
1513		// Python in HKLM, but we may or may not have permissions there.
1514		// Open the uninstall key with 'create' permissions - if this fails,
1515		// we don't have permission.
1516		if (!HasLocalMachinePrivs())
1517			hkey_root = HKEY_CURRENT_USER;
1518	} else {
1519		MessageBox(hwnd, "Don't know Python's installation type",
1520				   "Strange", MB_OK | MB_ICONSTOP);
1521		/* Default to wherever they can, but preferring HKLM */
1522		hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1523	}
1524}
1525
1526/* Return the installation scheme depending on Python version number */
1527SCHEME *GetScheme(int major, int minor)
1528{
1529	if (major > 2)
1530		return new_scheme;
1531	else if((major == 2) && (minor >= 2))
1532		return new_scheme;
1533	return old_scheme;
1534}
1535
1536BOOL CALLBACK
1537SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1538{
1539	LPNMHDR lpnm;
1540
1541	switch (msg) {
1542	case WM_INITDIALOG:
1543		if (hBitmap)
1544			SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1545					   IMAGE_BITMAP, (LPARAM)hBitmap);
1546		GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1547				   HKEY_LOCAL_MACHINE, target_version);
1548		GetPythonVersions(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1549				   HKEY_CURRENT_USER, target_version);
1550		{	/* select the last entry which is the highest python
1551			   version found */
1552			int count;
1553			count = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1554						    LB_GETCOUNT, 0, 0);
1555			if (count && count != LB_ERR)
1556				SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST, LB_SETCURSEL,
1557						    count-1, 0);
1558	    
1559			/* If a specific Python version is required,
1560			 * display a prominent notice showing this fact.
1561			 */
1562			if (target_version && target_version[0]) {
1563				char buffer[4096];
1564				wsprintf(buffer,
1565					 "Python %s is required for this package. "
1566					 "Select installation to use:",
1567					 target_version);
1568				SetDlgItemText(hwnd, IDC_TITLE, buffer);
1569			}
1570
1571			if (count == 0) {
1572				char Buffer[4096];
1573				char *msg;
1574				if (target_version && target_version[0]) {
1575					wsprintf(Buffer,
1576						 "Python version %s required, which was not found"
1577						 " in the registry.", target_version);
1578					msg = Buffer;
1579				} else
1580					msg = "No Python installation found in the registry.";
1581				MessageBox(hwnd, msg, "Cannot install",
1582					   MB_OK | MB_ICONSTOP);
1583			}
1584		}
1585		goto UpdateInstallDir;
1586		break;
1587
1588	case WM_COMMAND:
1589		switch (LOWORD(wParam)) {
1590/*
1591  case IDC_OTHERPYTHON:
1592  if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1593  target_version))
1594  goto UpdateInstallDir;
1595  break;
1596*/
1597		case IDC_VERSIONS_LIST:
1598			switch (HIWORD(wParam)) {
1599				int id;
1600			case LBN_SELCHANGE:
1601			  UpdateInstallDir:
1602				PropSheet_SetWizButtons(GetParent(hwnd),
1603							PSWIZB_BACK | PSWIZB_NEXT);
1604				id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1605							 LB_GETCURSEL, 0, 0);
1606				if (id == LB_ERR) {
1607					PropSheet_SetWizButtons(GetParent(hwnd),
1608								PSWIZB_BACK);
1609					SetDlgItemText(hwnd, IDC_PATH, "");
1610					SetDlgItemText(hwnd, IDC_INSTALL_PATH, "");
1611					strcpy(python_dir, "");
1612					strcpy(pythondll, "");
1613				} else {
1614					char *pbuf;
1615					int result;
1616					InstalledVersionInfo *ivi;
1617					PropSheet_SetWizButtons(GetParent(hwnd),
1618								PSWIZB_BACK | PSWIZB_NEXT);
1619					/* Get the python directory */
1620                    ivi = (InstalledVersionInfo *)
1621                                SendDlgItemMessage(hwnd,
1622									IDC_VERSIONS_LIST,
1623									LB_GETITEMDATA,
1624									id,
1625									0);
1626                    hkey_root = ivi->hkey;
1627					strcpy(python_dir, ivi->prefix);
1628					SetDlgItemText(hwnd, IDC_PATH, python_dir);
1629					/* retrieve the python version and pythondll to use */
1630					result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1631								     LB_GETTEXTLEN, (WPARAM)id, 0);
1632					pbuf = (char *)malloc(result + 1);
1633					if (pbuf) {
1634						/* guess the name of the python-dll */
1635						SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1636								    LB_GETTEXT, (WPARAM)id,
1637								    (LPARAM)pbuf);
1638						result = sscanf(pbuf, "Python Version %d.%d",
1639								 &py_major, &py_minor);
1640						if (result == 2) {
1641#ifdef _DEBUG
1642							wsprintf(pythondll, "python%d%d_d.dll",
1643								 py_major, py_minor);
1644#else
1645							wsprintf(pythondll, "python%d%d.dll",
1646								 py_major, py_minor);
1647#endif
1648						}
1649						free(pbuf);
1650					} else
1651						strcpy(pythondll, "");
1652					/* retrieve the scheme for this version */
1653					{
1654						char install_path[_MAX_PATH];
1655						SCHEME *scheme = GetScheme(py_major, py_minor);
1656						strcpy(install_path, python_dir);
1657						if (install_path[strlen(install_path)-1] != '\\')
1658							strcat(install_path, "\\");
1659						strcat(install_path, scheme[0].prefix);
1660						SetDlgItemText(hwnd, IDC_INSTALL_PATH, install_path);
1661					}
1662				}
1663			}
1664			break;
1665		}
1666		return 0;
1667
1668	case WM_NOTIFY:
1669		lpnm = (LPNMHDR) lParam;
1670
1671		switch (lpnm->code) {
1672			int id;
1673		case PSN_SETACTIVE:
1674			id = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
1675						 LB_GETCURSEL, 0, 0);
1676			if (id == LB_ERR)
1677				PropSheet_SetWizButtons(GetParent(hwnd),
1678							PSWIZB_BACK);
1679			else
1680				PropSheet_SetWizButtons(GetParent(hwnd),
1681							PSWIZB_BACK | PSWIZB_NEXT);
1682			break;
1683
1684		case PSN_WIZNEXT:
1685			break;
1686
1687		case PSN_WIZFINISH:
1688			break;
1689
1690		case PSN_RESET:
1691			break;
1692		
1693		default:
1694			break;
1695		}
1696	}
1697	return 0;
1698}
1699
1700static BOOL OpenLogfile(char *dir)
1701{
1702	char buffer[_MAX_PATH+1];
1703	time_t ltime;
1704	struct tm *now;
1705	long result;
1706	HKEY hKey, hSubkey;
1707	char subkey_name[256];
1708	static char KeyName[] = 
1709		"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1710	const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
1711	                        "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
1712	DWORD disposition;
1713
1714	/* Use Create, as the Uninstall subkey may not exist under HKCU.
1715	   Use CreateKeyEx, so we can specify a SAM specifying write access
1716	*/
1717		result = RegCreateKeyEx(hkey_root,
1718			      KeyName,
1719			      0, /* reserved */
1720			      NULL, /* class */
1721			      0, /* options */
1722			      KEY_CREATE_SUB_KEY, /* sam */
1723			      NULL, /* security */
1724			      &hKey, /* result key */
1725			      NULL); /* disposition */
1726	if (result != ERROR_SUCCESS) {
1727		if (result == ERROR_ACCESS_DENIED) {
1728			/* This should no longer be able to happen - we have already
1729			   checked if they have permissions in HKLM, and all users
1730			   should have write access to HKCU.
1731			*/
1732			MessageBox(GetFocus(),
1733				   "You do not seem to have sufficient access rights\n"
1734				   "on this machine to install this software",
1735				   NULL,
1736				   MB_OK | MB_ICONSTOP);
1737			return FALSE;
1738		} else {
1739			MessageBox(GetFocus(), KeyName, "Could not open key", MB_OK);
1740		}
1741	}
1742
1743	sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name);
1744	logfile = fopen(buffer, "a");
1745	time(&ltime);
1746	now = localtime(&ltime);
1747	strftime(buffer, sizeof(buffer),
1748		 "*** Installation started %Y/%m/%d %H:%M ***\n",
1749		 localtime(&ltime));
1750	fprintf(logfile, buffer);
1751	fprintf(logfile, "Source: %s\n", modulename);
1752
1753	/* Root key must be first entry processed by uninstaller. */
1754	fprintf(logfile, "999 Root Key: %s\n", root_name);
1755
1756	sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
1757
1758	result = RegCreateKeyEx(hKey, subkey_name,
1759				0, NULL, 0,
1760				KEY_WRITE,
1761				NULL,
1762				&hSubkey,
1763				&disposition);
1764
1765	if (result != ERROR_SUCCESS)
1766		MessageBox(GetFocus(), subkey_name, "Could not create key", MB_OK);
1767
1768	RegCloseKey(hKey);
1769
1770	if (disposition == REG_CREATED_NEW_KEY)
1771		fprintf(logfile, "020 Reg DB Key: [%s]%s\n", KeyName, subkey_name);
1772
1773	sprintf(buffer, "Python %d.%d %s", py_major, py_minor, title);
1774
1775	result = RegSetValueEx(hSubkey, "DisplayName",
1776			       0,
1777			       REG_SZ,
1778			       buffer,
1779			       strlen(buffer)+1);
1780
1781	if (result != ERROR_SUCCESS)
1782		MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1783
1784	fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1785		KeyName, subkey_name, "DisplayName", buffer);
1786
1787	{
1788		FILE *fp;
1789		sprintf(buffer, "%s\\Remove%s.exe", dir, meta_name);
1790		fp = fopen(buffer, "wb");
1791		fwrite(arc_data, exe_size, 1, fp);
1792		fclose(fp);
1793
1794		sprintf(buffer, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1795			dir, meta_name, dir, meta_name);
1796
1797		result = RegSetValueEx(hSubkey, "UninstallString",
1798				       0,
1799				       REG_SZ,
1800				       buffer,
1801				       strlen(buffer)+1);
1802	
1803		if (result != ERROR_SUCCESS)
1804			MessageBox(GetFocus(), buffer, "Could not set key value", MB_OK);
1805
1806		fprintf(logfile, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1807			KeyName, subkey_name, "UninstallString", buffer);
1808	}
1809	return TRUE;
1810}
1811
1812static void CloseLogfile(void)
1813{
1814	char buffer[_MAX_PATH+1];
1815	time_t ltime;
1816	struct tm *now;
1817
1818	time(&ltime);
1819	now = localtime(&ltime);
1820	strftime(buffer, sizeof(buffer),
1821		 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1822		 localtime(&ltime));
1823	fprintf(logfile, buffer);
1824	if (logfile)
1825		fclose(logfile);
1826}
1827
1828BOOL CALLBACK
1829InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1830{
1831	LPNMHDR lpnm;
1832	char Buffer[4096];
1833	SCHEME *scheme;
1834
1835	switch (msg) {
1836	case WM_INITDIALOG:
1837		if (hBitmap)
1838			SendDlgItemMessage(hwnd, IDC_BITMAP, STM_SETIMAGE,
1839					   IMAGE_BITMAP, (LPARAM)hBitmap);
1840		wsprintf(Buffer,
1841			  "Click Next to begin the installation of %s. "
1842			  "If you want to review or change any of your "
1843			  " installation settings, click Back. "
1844			  "Click Cancel to exit the wizard.",
1845			  meta_name);
1846		SetDlgItemText(hwnd, IDC_TITLE, Buffer);
1847		SetDlgItemText(hwnd, IDC_INFO, "Ready to install");
1848		break;
1849
1850	case WM_NUMFILES:
1851		SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, lParam);
1852		PumpMessages();
1853		return TRUE;
1854
1855	case WM_NEXTFILE:
1856		SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, wParam,
1857				    0);
1858		SetDlgItemText(hwnd, IDC_INFO, (LPSTR)lParam);
1859		PumpMessages();
1860		return TRUE;
1861
1862	case WM_NOTIFY:
1863		lpnm = (LPNMHDR) lParam;
1864
1865		switch (lpnm->code) {
1866		case PSN_SETACTIVE:
1867			PropSheet_SetWizButtons(GetParent(hwnd),
1868						PSWIZB_BACK | PSWIZB_NEXT);
1869			break;
1870
1871		case PSN_WIZFINISH:
1872			break;
1873
1874		case PSN_WIZNEXT:
1875			/* Handle a Next button click here */
1876			hDialog = hwnd;
1877			success = TRUE;
1878
1879			/* Disable the buttons while we work.  Sending CANCELTOCLOSE has
1880			  the effect of disabling the cancel button, which is a) as we
1881			  do everything synchronously we can't cancel, and b) the next
1882			  step is 'finished', when it is too late to cancel anyway.
1883			  The next step being 'Finished' means we also don't need to
1884			  restore the button state back */
1885			PropSheet_SetWizButtons(GetParent(hwnd), 0);
1886			SendMessage(GetParent(hwnd), PSM_CANCELTOCLOSE, 0, 0);
1887			/* Make sure the installation directory name ends in a */
1888			/* backslash */
1889			if (python_dir[strlen(python_dir)-1] != '\\')
1890				strcat(python_dir, "\\");
1891			/* Strip the trailing backslash again */
1892			python_dir[strlen(python_dir)-1] = '\0';
1893            
1894			CheckRootKey(hwnd);
1895	    
1896			if (!OpenLogfile(python_dir))
1897				break;
1898
1899/*
1900 * The scheme we have to use depends on the Python version...
1901 if sys.version < "2.2":
1902 WINDOWS_SCHEME = {
1903 'purelib': '$base',
1904 'platlib': '$base',
1905 'headers': '$base/Include/$dist_name',
1906 'scripts': '$base/Scripts',
1907 'data'   : '$base',
1908 }
1909 else:
1910 WINDOWS_SCHEME = {
1911 'purelib': '$base/Lib/site-packages',
1912 'platlib': '$base/Lib/site-packages',
1913 'headers': '$base/Include/$dist_name',
1914 'scripts': '$base/Scripts',
1915 'data'   : …

Large files files are truncated, but you can click here to view the full file