ยปCore Development>Code coverage>PC/bdist_wininst/install.c

Python code coverage for PC/bdist_wininst/install.c

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