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.
6 IF CHANGES TO THIS FILE ARE CHECKED INTO PYTHON CVS, THE RECOMPILED BINARIES
7 MUST BE CHECKED IN AS WELL!
11 * Written by Thomas Heller, May 2000
17 * Windows Installer program for distutils.
19 * (a kind of self-extracting zip-file)
21 * At runtime, the exefile has appended:
22 * - compressed setup-data in ini-format, containing the following sections:
25 * author_email=gward@python.net
26 * description=Python Distribution Utilities
29 * url=http://www.python.org/sigs/distutils-sig/
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
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
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
55 * Includes now an uninstaller.
61 * display some explanation when no python version is found
62 * instead showing the user an empty listbox to select something from.
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
68 * - install a help-button, which will display something meaningful
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(?)
75 * - evolve this into a full blown installer (???)
91 #include <sys/types.h>
99 /* Only for debugging!
100 static int dprintf(char *fmt, ...)
106 va_start(marker, fmt);
107 result = wvsprintf(Buffer, fmt, marker);
108 OutputDebugString(Buffer);
113 /* Bah: global variables */
116 char modulename
[MAX_PATH
];
121 char *ini_file
; /* Full pathname of ini-file */
123 char info
[4096]; /* [Setup] info= */
124 char title
[80]; /* [Setup] title=, contains package name
125 including version: "Distutils-1.0.1" */
126 char target_version
[10]; /* [Setup] target_version=, required python
127 version or empty string */
128 char build_info
[80]; /* [Setup] build_info=, distutils version
131 char meta_name
[80]; /* package name without version like
133 char install_script
[MAX_PATH
];
134 char *pre_install_script
; /* run before we install a single file */
137 int py_major
, py_minor
; /* Python version selected for installation */
139 char *arc_data
; /* memory mapped archive */
140 DWORD arc_size
; /* number of bytes in archive */
141 int exe_size
; /* number of bytes for exe-file portion */
142 char python_dir
[MAX_PATH
];
143 char pythondll
[MAX_PATH
];
144 BOOL pyc_compile
, pyo_compile
;
145 /* Either HKLM or HKCU, depending on where Python itself is registered, and
146 the permissions of the current user. */
147 HKEY hkey_root
= (HKEY
)-1;
149 BOOL success
; /* Installation successfull? */
150 char *failure_reason
= NULL
;
156 #define WM_NUMFILES WM_USER+1
157 /* wParam: 0, lParam: total number of files */
158 #define WM_NEXTFILE WM_USER+2
159 /* wParam: number of this file */
160 /* lParam: points to pathname */
162 static BOOL
notify(int code
, char *fmt
, ...);
164 /* Note: If scheme.prefix is nonempty, it must end with a '\'! */
165 /* Note: purelib must be the FIRST entry! */
166 SCHEME old_scheme
[] = {
169 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
170 { "SCRIPTS", "Scripts\\" },
175 SCHEME new_scheme
[] = {
176 { "PURELIB", "Lib\\site-packages\\" },
177 { "PLATLIB", "Lib\\site-packages\\" },
178 { "HEADERS", "" }, /* 'Include/dist_name' part already in archive */
179 { "SCRIPTS", "Scripts\\" },
184 static void unescape(char *dst
, char *src
, unsigned size
)
189 while (src
&& *src
&& (size
> 2)) {
203 case '0': case '1': case '2': case '3':
204 ch
= (char)strtol(src
, &eon
, 8);
221 static struct tagFile
{
223 struct tagFile
*next
;
226 static void set_failure_reason(char *reason
)
229 free(failure_reason
);
230 failure_reason
= strdup(reason
);
233 static char *get_failure_reason()
236 return "Installation failed.";
237 return failure_reason
;
240 static void add_to_filelist(char *path
)
243 p
= (struct tagFile
*)malloc(sizeof(struct tagFile
));
244 p
->path
= strdup(path
);
249 static int do_compile_files(int (__cdecl
* PyRun_SimpleString
)(char *),
254 char Buffer
[MAX_PATH
+ 64];
263 SendDlgItemMessage(hDialog
, IDC_PROGRESS
, PBM_SETRANGE
, 0,
264 MAKELPARAM(0, total
));
265 SendDlgItemMessage(hDialog
, IDC_PROGRESS
, PBM_SETPOS
, 0, 0);
272 "import py_compile; py_compile.compile (r'%s')",
274 if (PyRun_SimpleString(Buffer
)) {
277 /* We send the notification even if the files could not
278 * be created so that the uninstaller will remove them
279 * in case they are created later.
281 wsprintf(Buffer
, "%s%c", p
->path
, optimize
? 'o' : 'c');
282 notify(FILE_CREATED
, Buffer
);
284 SendDlgItemMessage(hDialog
, IDC_PROGRESS
, PBM_SETPOS
, n
, 0);
285 SetDlgItemText(hDialog
, IDC_INFO
, p
->path
);
291 #define DECLPROC(dll, result, name, args)\
292 typedef result (*__PROC__##name) args;\
293 result (*name)args = (__PROC__##name)GetProcAddress(dll, #name)
296 #define DECLVAR(dll, type, name)\
297 type *name = (type*)GetProcAddress(dll, #name)
299 typedef void PyObject
;
303 * Returns number of files which failed to compile,
304 * -1 if python could not be loaded at all
306 static int compile_filelist(HINSTANCE hPython
, BOOL optimize_flag
)
308 DECLPROC(hPython
, void, Py_Initialize
, (void));
309 DECLPROC(hPython
, void, Py_SetProgramName
, (char *));
310 DECLPROC(hPython
, void, Py_Finalize
, (void));
311 DECLPROC(hPython
, int, PyRun_SimpleString
, (char *));
312 DECLPROC(hPython
, PyObject
*, PySys_GetObject
, (char *));
313 DECLVAR(hPython
, int, Py_OptimizeFlag
);
316 struct tagFile
*p
= file_list
;
321 if (!Py_Initialize
|| !Py_SetProgramName
|| !Py_Finalize
)
324 if (!PyRun_SimpleString
|| !PySys_GetObject
|| !Py_OptimizeFlag
)
327 *Py_OptimizeFlag
= optimize_flag
? 1 : 0;
328 Py_SetProgramName(modulename
);
331 errors
+= do_compile_files(PyRun_SimpleString
, optimize_flag
);
337 typedef PyObject
*(*PyCFunction
)(PyObject
*, PyObject
*);
345 typedef struct PyMethodDef PyMethodDef
;
347 void *(*g_Py_BuildValue
)(char *, ...);
348 int (*g_PyArg_ParseTuple
)(PyObject
*, char *, ...);
350 PyObject
*g_PyExc_ValueError
;
351 PyObject
*g_PyExc_OSError
;
353 PyObject
*(*g_PyErr_Format
)(PyObject
*, char *, ...);
355 #define DEF_CSIDL(name) { name, #name }
361 /* Startup menu for all users.
363 DEF_CSIDL(CSIDL_COMMON_STARTMENU
),
365 DEF_CSIDL(CSIDL_STARTMENU
),
367 /* DEF_CSIDL(CSIDL_COMMON_APPDATA), */
368 /* DEF_CSIDL(CSIDL_LOCAL_APPDATA), */
369 /* Repository for application-specific data.
370 Needs Internet Explorer 4.0 */
371 DEF_CSIDL(CSIDL_APPDATA
),
373 /* The desktop for all users.
375 DEF_CSIDL(CSIDL_COMMON_DESKTOPDIRECTORY
),
377 DEF_CSIDL(CSIDL_DESKTOPDIRECTORY
),
379 /* Startup folder for all users.
381 DEF_CSIDL(CSIDL_COMMON_STARTUP
),
382 /* Startup folder. */
383 DEF_CSIDL(CSIDL_STARTUP
),
385 /* Programs item in the start menu for all users.
387 DEF_CSIDL(CSIDL_COMMON_PROGRAMS
),
388 /* Program item in the user's start menu. */
389 DEF_CSIDL(CSIDL_PROGRAMS
),
391 /* DEF_CSIDL(CSIDL_PROGRAM_FILES_COMMON), */
392 /* DEF_CSIDL(CSIDL_PROGRAM_FILES), */
394 /* Virtual folder containing fonts. */
395 DEF_CSIDL(CSIDL_FONTS
),
398 #define DIM(a) (sizeof(a) / sizeof((a)[0]))
400 static PyObject
*FileCreated(PyObject
*self
, PyObject
*args
)
403 if (!g_PyArg_ParseTuple(args
, "s", &path
))
405 notify(FILE_CREATED
, path
);
406 return g_Py_BuildValue("");
409 static PyObject
*DirectoryCreated(PyObject
*self
, PyObject
*args
)
412 if (!g_PyArg_ParseTuple(args
, "s", &path
))
414 notify(DIR_CREATED
, path
);
415 return g_Py_BuildValue("");
418 static PyObject
*GetSpecialFolderPath(PyObject
*self
, PyObject
*args
)
421 char lpszPath
[MAX_PATH
];
423 static HRESULT (WINAPI
*My_SHGetSpecialFolderPath
)(HWND hwnd
,
428 if (!My_SHGetSpecialFolderPath
) {
429 HINSTANCE hLib
= LoadLibrary("shell32.dll");
431 g_PyErr_Format(g_PyExc_OSError
,
432 "function not available");
435 My_SHGetSpecialFolderPath
= (BOOL (WINAPI
*)(HWND
, LPTSTR
,
438 "SHGetSpecialFolderPathA");
441 if (!g_PyArg_ParseTuple(args
, "s", &name
))
444 if (!My_SHGetSpecialFolderPath
) {
445 g_PyErr_Format(g_PyExc_OSError
, "function not available");
449 for (i
= 0; i
< DIM(csidl_names
); ++i
) {
450 if (0 == strcmpi(csidl_names
[i
].name
, name
)) {
452 nFolder
= csidl_names
[i
].nFolder
;
453 if (My_SHGetSpecialFolderPath(NULL
, lpszPath
,
455 return g_Py_BuildValue("s", lpszPath
);
457 g_PyErr_Format(g_PyExc_OSError
,
458 "no such folder (%s)", name
);
464 g_PyErr_Format(g_PyExc_ValueError
, "unknown CSIDL (%s)", name
);
468 static PyObject
*CreateShortcut(PyObject
*self
, PyObject
*args
)
470 char *path
; /* path and filename */
474 char *arguments
= NULL
;
475 char *iconpath
= NULL
;
477 char *workdir
= NULL
;
479 WCHAR wszFilename
[MAX_PATH
];
481 IShellLink
*ps1
= NULL
;
482 IPersistFile
*pPf
= NULL
;
486 hr
= CoInitialize(NULL
);
488 g_PyErr_Format(g_PyExc_OSError
,
489 "CoInitialize failed, error 0x%x", hr
);
493 if (!g_PyArg_ParseTuple(args
, "sss|sssi",
494 &path
, &description
, &filename
,
495 &arguments
, &workdir
, &iconpath
, &iconindex
))
498 hr
= CoCreateInstance(&CLSID_ShellLink
,
500 CLSCTX_INPROC_SERVER
,
504 g_PyErr_Format(g_PyExc_OSError
,
505 "CoCreateInstance failed, error 0x%x", hr
);
509 hr
= ps1
->lpVtbl
->QueryInterface(ps1
, &IID_IPersistFile
,
512 g_PyErr_Format(g_PyExc_OSError
,
513 "QueryInterface(IPersistFile) error 0x%x", hr
);
518 hr
= ps1
->lpVtbl
->SetPath(ps1
, path
);
520 g_PyErr_Format(g_PyExc_OSError
,
521 "SetPath() failed, error 0x%x", hr
);
525 hr
= ps1
->lpVtbl
->SetDescription(ps1
, description
);
527 g_PyErr_Format(g_PyExc_OSError
,
528 "SetDescription() failed, error 0x%x", hr
);
533 hr
= ps1
->lpVtbl
->SetArguments(ps1
, arguments
);
535 g_PyErr_Format(g_PyExc_OSError
,
536 "SetArguments() error 0x%x", hr
);
542 hr
= ps1
->lpVtbl
->SetIconLocation(ps1
, iconpath
, iconindex
);
544 g_PyErr_Format(g_PyExc_OSError
,
545 "SetIconLocation() error 0x%x", hr
);
551 hr
= ps1
->lpVtbl
->SetWorkingDirectory(ps1
, workdir
);
553 g_PyErr_Format(g_PyExc_OSError
,
554 "SetWorkingDirectory() error 0x%x", hr
);
559 MultiByteToWideChar(CP_ACP
, 0,
561 wszFilename
, MAX_PATH
);
563 hr
= pPf
->lpVtbl
->Save(pPf
, wszFilename
, TRUE
);
565 g_PyErr_Format(g_PyExc_OSError
,
566 "Failed to create shortcut '%s' - error 0x%x", filename
, hr
);
570 pPf
->lpVtbl
->Release(pPf
);
571 ps1
->lpVtbl
->Release(ps1
);
573 return g_Py_BuildValue("");
577 pPf
->lpVtbl
->Release(pPf
);
580 ps1
->lpVtbl
->Release(ps1
);
587 static PyObject
*PyMessageBox(PyObject
*self
, PyObject
*args
)
590 char *text
, *caption
;
592 if (!g_PyArg_ParseTuple(args
, "ssi", &text
, &caption
, &flags
))
594 rc
= MessageBox(GetFocus(), text
, caption
, flags
);
595 return g_Py_BuildValue("i", rc
);
598 static PyObject
*GetRootHKey(PyObject
*self
)
600 return g_Py_BuildValue("l", hkey_root
);
603 #define METH_VARARGS 0x0001
604 #define METH_NOARGS 0x0004
605 typedef PyObject
*(*PyCFunction
)(PyObject
*, PyObject
*);
607 PyMethodDef meth
[] = {
608 {"create_shortcut", CreateShortcut
, METH_VARARGS
, NULL
},
609 {"get_special_folder_path", GetSpecialFolderPath
, METH_VARARGS
, NULL
},
610 {"get_root_hkey", (PyCFunction
)GetRootHKey
, METH_NOARGS
, NULL
},
611 {"file_created", FileCreated
, METH_VARARGS
, NULL
},
612 {"directory_created", DirectoryCreated
, METH_VARARGS
, NULL
},
613 {"message_box", PyMessageBox
, METH_VARARGS
, NULL
},
616 static HINSTANCE
LoadPythonDll(char *fname
)
618 char fullpath
[_MAX_PATH
];
619 LONG size
= sizeof(fullpath
);
620 char subkey_name
[80];
621 char buffer
[260 + 12];
624 /* make sure PYTHONHOME is set, to that sys.path is initialized correctly */
625 wsprintf(buffer
, "PYTHONHOME=%s", python_dir
);
627 h
= LoadLibrary(fname
);
630 wsprintf(subkey_name
,
631 "SOFTWARE\\Python\\PythonCore\\%d.%d\\InstallPath",
633 if (ERROR_SUCCESS
!= RegQueryValue(HKEY_CURRENT_USER
, subkey_name
,
636 strcat(fullpath
, "\\");
637 strcat(fullpath
, fname
);
638 return LoadLibrary(fullpath
);
641 static int prepare_script_environment(HINSTANCE hPython
)
644 DECLPROC(hPython
, PyObject
*, PyImport_ImportModule
, (char *));
645 DECLPROC(hPython
, int, PyObject_SetAttrString
, (PyObject
*, char *, PyObject
*));
646 DECLPROC(hPython
, PyObject
*, PyObject_GetAttrString
, (PyObject
*, char *));
647 DECLPROC(hPython
, PyObject
*, PyCFunction_New
, (PyMethodDef
*, PyObject
*));
648 DECLPROC(hPython
, PyObject
*, Py_BuildValue
, (char *, ...));
649 DECLPROC(hPython
, int, PyArg_ParseTuple
, (PyObject
*, char *, ...));
650 DECLPROC(hPython
, PyObject
*, PyErr_Format
, (PyObject
*, char *));
651 if (!PyImport_ImportModule
|| !PyObject_GetAttrString
||
652 !PyObject_SetAttrString
|| !PyCFunction_New
)
654 if (!Py_BuildValue
|| !PyArg_ParseTuple
|| !PyErr_Format
)
657 mod
= PyImport_ImportModule("__builtin__");
660 g_PyExc_ValueError
= PyObject_GetAttrString(mod
, "ValueError");
661 g_PyExc_OSError
= PyObject_GetAttrString(mod
, "OSError");
662 for (i
= 0; i
< DIM(meth
); ++i
) {
663 PyObject_SetAttrString(mod
, meth
[i
].ml_name
,
664 PyCFunction_New(&meth
[i
], NULL
));
667 g_Py_BuildValue
= Py_BuildValue
;
668 g_PyArg_ParseTuple
= PyArg_ParseTuple
;
669 g_PyErr_Format
= PyErr_Format
;
675 * This function returns one of the following error codes:
676 * 1 if the Python-dll does not export the functions we need
677 * 2 if no install-script is specified in pathname
678 * 3 if the install-script file could not be opened
679 * the return value of PyRun_SimpleString() otherwise,
680 * which is 0 if everything is ok, -1 if an exception had occurred
681 * in the install-script.
685 run_installscript(HINSTANCE hPython
, char *pathname
, int argc
, char **argv
)
687 DECLPROC(hPython
, void, Py_Initialize
, (void));
688 DECLPROC(hPython
, int, PySys_SetArgv
, (int, char **));
689 DECLPROC(hPython
, int, PyRun_SimpleString
, (char *));
690 DECLPROC(hPython
, void, Py_Finalize
, (void));
691 DECLPROC(hPython
, PyObject
*, Py_BuildValue
, (char *, ...));
692 DECLPROC(hPython
, PyObject
*, PyCFunction_New
,
693 (PyMethodDef
*, PyObject
*));
694 DECLPROC(hPython
, int, PyArg_ParseTuple
, (PyObject
*, char *, ...));
695 DECLPROC(hPython
, PyObject
*, PyErr_Format
, (PyObject
*, char *));
700 if (!Py_Initialize
|| !PySys_SetArgv
701 || !PyRun_SimpleString
|| !Py_Finalize
)
704 if (!Py_BuildValue
|| !PyArg_ParseTuple
|| !PyErr_Format
)
707 if (!PyCFunction_New
|| !PyArg_ParseTuple
|| !PyErr_Format
)
710 if (pathname
== NULL
|| pathname
[0] == '\0')
713 fh
= open(pathname
, _O_RDONLY
);
715 fprintf(stderr
, "Could not open postinstall-script %s\n",
720 SetDlgItemText(hDialog
, IDC_INFO
, "Running Script...");
724 prepare_script_environment(hPython
);
725 PySys_SetArgv(argc
, argv
);
728 struct _stat statbuf
;
729 if(0 == _fstat(fh
, &statbuf
)) {
730 char *script
= alloca(statbuf
.st_size
+ 5);
731 int n
= read(fh
, script
, statbuf
.st_size
);
735 result
= PyRun_SimpleString(script
);
746 static int do_run_simple_script(HINSTANCE hPython
, char *script
)
749 DECLPROC(hPython
, void, Py_Initialize
, (void));
750 DECLPROC(hPython
, void, Py_SetProgramName
, (char *));
751 DECLPROC(hPython
, void, Py_Finalize
, (void));
752 DECLPROC(hPython
, int, PyRun_SimpleString
, (char *));
753 DECLPROC(hPython
, void, PyErr_Print
, (void));
755 if (!Py_Initialize
|| !Py_SetProgramName
|| !Py_Finalize
||
756 !PyRun_SimpleString
|| !PyErr_Print
)
759 Py_SetProgramName(modulename
);
761 prepare_script_environment(hPython
);
762 rc
= PyRun_SimpleString(script
);
769 static int run_simple_script(char *script
)
774 tempname
= tempnam(NULL
, NULL
);
775 freopen(tempname
, "a", stderr
);
776 freopen(tempname
, "a", stdout
);
778 hPython
= LoadPythonDll(pythondll
);
780 set_failure_reason("Can't load Python for pre-install script");
783 rc
= do_run_simple_script(hPython
, script
);
784 FreeLibrary(hPython
);
789 /* We only care about the output when we fail. If the script works
790 OK, then we discard it
795 const char *prefix
= "Running the pre-installation script failed\r\n";
796 int prefix_len
= strlen(prefix
);
797 FILE *fp
= fopen(tempname
, "rb");
798 fseek(fp
, 0, SEEK_END
);
799 err_buf_size
= ftell(fp
);
800 fseek(fp
, 0, SEEK_SET
);
801 err_buf
= malloc(prefix_len
+ err_buf_size
+ 1);
804 strcpy(err_buf
, prefix
);
805 n
= fread(err_buf
+prefix_len
, 1, err_buf_size
, fp
);
806 err_buf
[prefix_len
+n
] = '\0';
808 set_failure_reason(err_buf
);
811 set_failure_reason("Out of memory!");
819 static BOOL
SystemError(int error
, char *msg
)
827 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
828 FORMAT_MESSAGE_FROM_SYSTEM
,
831 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
836 strncpy(Buffer
, lpMsgBuf
, sizeof(Buffer
));
841 _snprintf(Buffer
+n
, sizeof(Buffer
)-n
, msg
);
842 MessageBox(hwndMain
, Buffer
, "Runtime Error", MB_OK
| MB_ICONSTOP
);
846 static BOOL
notify (int code
, char *fmt
, ...)
854 va_start(marker
, fmt
);
855 _vsnprintf(Buffer
, sizeof(Buffer
), fmt
, marker
);
862 /* Information notification */
865 fprintf(logfile
, "100 Made Dir: %s\n", fmt
);
870 fprintf(logfile
, "200 File Copy: %s\n", fmt
);
871 goto add_to_filelist_label
;
874 case FILE_OVERWRITTEN
:
876 fprintf(logfile
, "200 File Overwrite: %s\n", fmt
);
877 add_to_filelist_label
:
878 if ((cp
= strrchr(fmt
, '.')) && (0 == strcmp (cp
, ".py")))
879 add_to_filelist(fmt
);
884 MessageBox(GetFocus(), Buffer
, "Error",
885 MB_OK
| MB_ICONWARNING
);
889 SystemError(GetLastError(), Buffer
);
893 a
= va_arg(marker
, int);
894 b
= va_arg(marker
, int);
895 SendMessage(hDialog
, WM_NUMFILES
, 0, MAKELPARAM(0, a
));
896 SendMessage(hDialog
, WM_NEXTFILE
, b
,(LPARAM
)fmt
);
903 static char *MapExistingFile(char *pathname
, DWORD
*psize
)
905 HANDLE hFile
, hFileMapping
;
906 DWORD nSizeLow
, nSizeHigh
;
909 hFile
= CreateFile(pathname
,
910 GENERIC_READ
, FILE_SHARE_READ
, NULL
,
912 FILE_ATTRIBUTE_NORMAL
, NULL
);
913 if (hFile
== INVALID_HANDLE_VALUE
)
915 nSizeLow
= GetFileSize(hFile
, &nSizeHigh
);
916 hFileMapping
= CreateFileMapping(hFile
,
917 NULL
, PAGE_READONLY
, 0, 0, NULL
);
920 if (hFileMapping
== INVALID_HANDLE_VALUE
)
923 data
= MapViewOfFile(hFileMapping
,
924 FILE_MAP_READ
, 0, 0, 0);
926 CloseHandle(hFileMapping
);
932 static void create_bitmap(HWND hwnd
)
934 BITMAPFILEHEADER
*bfh
;
946 bfh
= (BITMAPFILEHEADER
*)bitmap_bytes
;
947 bi
= (BITMAPINFO
*)(bitmap_bytes
+ sizeof(BITMAPFILEHEADER
));
949 hBitmap
= CreateDIBitmap(hdc
,
952 bitmap_bytes
+ bfh
->bfOffBits
,
955 ReleaseDC(hwnd
, hdc
);
958 /* Extract everything we need to begin the installation. Currently this
959 is the INI filename with install data, and the raw pre-install script
961 static BOOL
ExtractInstallData(char *data
, DWORD size
, int *pexe_size
,
962 char **out_ini_file
, char **out_preinstall_script
)
964 /* read the end of central directory record */
965 struct eof_cdir
*pe
= (struct eof_cdir
*)&data
[size
- sizeof
968 int arc_start
= size
- sizeof (struct eof_cdir
) - pe
->nBytesCDir
-
971 int ofs
= arc_start
- sizeof (struct meta_data_hdr
);
973 /* read meta_data info */
974 struct meta_data_hdr
*pmd
= (struct meta_data_hdr
*)&data
[ofs
];
977 char tempdir
[MAX_PATH
];
979 /* ensure that if we fail, we don't have garbage out pointers */
980 *out_ini_file
= *out_preinstall_script
= NULL
;
982 if (pe
->tag
!= 0x06054b50) {
986 if (pmd
->tag
!= 0x1234567B) {
987 return SystemError(0,
988 "Invalid cfgdata magic number (see bdist_wininst.py)");
994 if (pmd
->bitmap_size
) {
995 /* Store pointer to bitmap bytes */
996 bitmap_bytes
= (char *)pmd
- pmd
->uncomp_size
- pmd
->bitmap_size
;
999 *pexe_size
= ofs
- pmd
->uncomp_size
- pmd
->bitmap_size
;
1001 src
= ((char *)pmd
) - pmd
->uncomp_size
;
1002 ini_file
= malloc(MAX_PATH
); /* will be returned, so do not free it */
1005 if (!GetTempPath(sizeof(tempdir
), tempdir
)
1006 || !GetTempFileName(tempdir
, "~du", 0, ini_file
)) {
1007 SystemError(GetLastError(),
1008 "Could not create temporary file");
1012 dst
= map_new_file(CREATE_ALWAYS
, ini_file
, NULL
, pmd
->uncomp_size
,
1013 0, 0, NULL
/*notify*/);
1016 /* Up to the first \0 is the INI file data. */
1017 strncpy(dst
, src
, pmd
->uncomp_size
);
1018 src
+= strlen(dst
) + 1;
1019 /* Up to next \0 is the pre-install script */
1020 *out_preinstall_script
= strdup(src
);
1021 *out_ini_file
= ini_file
;
1022 UnmapViewOfFile(dst
);
1026 static void PumpMessages(void)
1029 while (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
1030 TranslateMessage(&msg
);
1031 DispatchMessage(&msg
);
1036 WindowProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1044 hdc
= BeginPaint(hwnd
, &ps
);
1045 h
= GetSystemMetrics(SM_CYSCREEN
) / 10;
1046 hFont
= CreateFont(h
, 0, 0, 0, 700, TRUE
,
1047 0, 0, 0, 0, 0, 0, 0, "Times Roman");
1048 hFont
= SelectObject(hdc
, hFont
);
1049 SetBkMode(hdc
, TRANSPARENT
);
1050 TextOut(hdc
, 15, 15, title
, strlen(title
));
1051 SetTextColor(hdc
, RGB(255, 255, 255));
1052 TextOut(hdc
, 10, 10, title
, strlen(title
));
1053 DeleteObject(SelectObject(hdc
, hFont
));
1054 EndPaint(hwnd
, &ps
);
1057 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
1060 static HWND
CreateBackground(char *title
)
1066 wc
.style
= CS_VREDRAW
| CS_HREDRAW
;
1067 wc
.lpfnWndProc
= WindowProc
;
1070 wc
.hInstance
= GetModuleHandle(NULL
);
1072 wc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1073 wc
.hbrBackground
= CreateSolidBrush(RGB(0, 0, 128));
1074 wc
.lpszMenuName
= NULL
;
1075 wc
.lpszClassName
= "SetupWindowClass";
1077 if (!RegisterClass(&wc
))
1078 MessageBox(hwndMain
,
1079 "Could not register window class",
1080 "Setup.exe", MB_OK
);
1082 wsprintf(buffer
, "Setup %s", title
);
1083 hwnd
= CreateWindow("SetupWindowClass",
1087 GetSystemMetrics(SM_CXFULLSCREEN
),
1088 GetSystemMetrics(SM_CYFULLSCREEN
),
1091 GetModuleHandle(NULL
),
1093 ShowWindow(hwnd
, SW_SHOWMAXIMIZED
);
1099 * Center a window on the screen
1101 static void CenterWindow(HWND hwnd
)
1106 GetWindowRect(hwnd
, &rc
);
1107 w
= GetSystemMetrics(SM_CXSCREEN
);
1108 h
= GetSystemMetrics(SM_CYSCREEN
);
1110 (w
- (rc
.right
-rc
.left
))/2,
1111 (h
- (rc
.bottom
-rc
.top
))/2,
1112 rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, FALSE
);
1118 IntroDlgProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1125 create_bitmap(hwnd
);
1127 SendDlgItemMessage(hwnd
, IDC_BITMAP
, STM_SETIMAGE
,
1128 IMAGE_BITMAP
, (LPARAM
)hBitmap
);
1129 CenterWindow(GetParent(hwnd
));
1131 "This Wizard will install %s on your computer. "
1132 "Click Next to continue "
1133 "or Cancel to exit the Setup Wizard.",
1135 SetDlgItemText(hwnd
, IDC_TITLE
, Buffer
);
1136 SetDlgItemText(hwnd
, IDC_INTRO_TEXT
, info
);
1137 SetDlgItemText(hwnd
, IDC_BUILD_INFO
, build_info
);
1141 lpnm
= (LPNMHDR
) lParam
;
1143 switch (lpnm
->code
) {
1145 PropSheet_SetWizButtons(GetParent(hwnd
), PSWIZB_NEXT
);
1161 #ifdef USE_OTHER_PYTHON_VERSIONS
1162 /* These are really private variables used to communicate
1163 * between StatusRoutine and CheckPythonExe
1165 char bound_image_dll
[_MAX_PATH
];
1166 int bound_image_major
;
1167 int bound_image_minor
;
1169 static BOOL __stdcall
StatusRoutine(IMAGEHLP_STATUS_REASON reason
,
1175 char fname
[_MAX_PATH
];
1179 case BindOutOfMemory
:
1180 case BindRvaToVaFailed
:
1181 case BindNoRoomInImage
:
1182 case BindImportProcedureFailed
:
1185 case BindImportProcedure
:
1187 case BindForwarderNOT
:
1188 case BindImageModified
:
1189 case BindExpandFileHeaders
:
1190 case BindImageComplete
:
1191 case BindSymbolsNotUpdated
:
1192 case BindMismatchedSymbols
:
1193 case BindImportModuleFailed
:
1196 case BindImportModule
:
1197 if (1 == sscanf(DllName
, "python%d", &int_version
)) {
1198 SearchPath(NULL
, DllName
, NULL
, sizeof(fname
),
1200 strcpy(bound_image_dll
, fname
);
1201 bound_image_major
= int_version
/ 10;
1202 bound_image_minor
= int_version
% 10;
1203 OutputDebugString("BOUND ");
1204 OutputDebugString(fname
);
1205 OutputDebugString("\n");
1214 static LPSTR
get_sys_prefix(LPSTR exe
, LPSTR dll
)
1216 void (__cdecl
* Py_Initialize
)(void);
1217 void (__cdecl
* Py_SetProgramName
)(char *);
1218 void (__cdecl
* Py_Finalize
)(void);
1219 void* (__cdecl
* PySys_GetObject
)(char *);
1220 void (__cdecl
* PySys_SetArgv
)(int, char **);
1221 char* (__cdecl
* Py_GetPrefix
)(void);
1222 char* (__cdecl
* Py_GetPath
)(void);
1224 LPSTR prefix
= NULL
;
1225 int (__cdecl
* PyRun_SimpleString
)(char *);
1229 wsprintf(Buffer
, "PYTHONHOME=%s", exe
);
1230 *strrchr(Buffer
, '\\') = '\0';
1231 // MessageBox(GetFocus(), Buffer, "PYTHONHOME", MB_OK);
1233 _putenv("PYTHONPATH=");
1236 hPython
= LoadLibrary(dll
);
1239 Py_Initialize
= (void (*)(void))GetProcAddress
1240 (hPython
,"Py_Initialize");
1242 PySys_SetArgv
= (void (*)(int, char **))GetProcAddress
1243 (hPython
,"PySys_SetArgv");
1245 PyRun_SimpleString
= (int (*)(char *))GetProcAddress
1246 (hPython
,"PyRun_SimpleString");
1248 Py_SetProgramName
= (void (*)(char *))GetProcAddress
1249 (hPython
,"Py_SetProgramName");
1251 PySys_GetObject
= (void* (*)(char *))GetProcAddress
1252 (hPython
,"PySys_GetObject");
1254 Py_GetPrefix
= (char * (*)(void))GetProcAddress
1255 (hPython
,"Py_GetPrefix");
1257 Py_GetPath
= (char * (*)(void))GetProcAddress
1258 (hPython
,"Py_GetPath");
1260 Py_Finalize
= (void (*)(void))GetProcAddress(hPython
,
1262 Py_SetProgramName(exe
);
1264 PySys_SetArgv(1, &exe
);
1266 MessageBox(GetFocus(), Py_GetPrefix(), "PREFIX", MB_OK
);
1267 MessageBox(GetFocus(), Py_GetPath(), "PATH", MB_OK
);
1270 FreeLibrary(hPython
);
1276 CheckPythonExe(LPSTR pathname
, LPSTR version
, int *pmajor
, int *pminor
)
1278 bound_image_dll
[0] = '\0';
1279 if (!BindImageEx(BIND_NO_BOUND_IMPORTS
| BIND_NO_UPDATE
| BIND_ALL_IMAGES
,
1284 return SystemError(0, "Could not bind image");
1285 if (bound_image_dll
[0] == '\0')
1286 return SystemError(0, "Does not seem to be a python executable");
1287 *pmajor
= bound_image_major
;
1288 *pminor
= bound_image_minor
;
1289 if (version
&& *version
) {
1290 char core_version
[12];
1291 wsprintf(core_version
, "%d.%d", bound_image_major
, bound_image_minor
);
1292 if (strcmp(version
, core_version
))
1293 return SystemError(0, "Wrong Python version");
1295 get_sys_prefix(pathname
, bound_image_dll
);
1300 * Browse for other python versions. Insert it into the listbox specified
1301 * by hwnd. version, if not NULL or empty, is the version required.
1303 static BOOL
GetOtherPythonVersion(HWND hwnd
, LPSTR version
)
1305 char vers_name
[_MAX_PATH
+ 80];
1308 char pathname
[_MAX_PATH
];
1311 strcpy(pathname
, "python.exe");
1313 memset(&of
, 0, sizeof(of
));
1314 of
.lStructSize
= sizeof(OPENFILENAME
);
1315 of
.hwndOwner
= GetParent(hwnd
);
1316 of
.hInstance
= NULL
;
1317 of
.lpstrFilter
= "python.exe\0python.exe\0";
1318 of
.lpstrCustomFilter
= NULL
;
1319 of
.nMaxCustFilter
= 0;
1320 of
.nFilterIndex
= 1;
1321 of
.lpstrFile
= pathname
;
1322 of
.nMaxFile
= sizeof(pathname
);
1323 of
.lpstrFileTitle
= NULL
;
1324 of
.nMaxFileTitle
= 0;
1325 of
.lpstrInitialDir
= NULL
;
1326 of
.lpstrTitle
= "Python executable";
1327 of
.Flags
= OFN_FILEMUSTEXIST
| OFN_PATHMUSTEXIST
;
1328 of
.lpstrDefExt
= "exe";
1330 result
= GetOpenFileName(&of
);
1333 if (!CheckPythonExe(pathname
, version
, &major
, &minor
)) {
1336 *strrchr(pathname
, '\\') = '\0';
1337 wsprintf(vers_name
, "Python Version %d.%d in %s",
1338 major
, minor
, pathname
);
1339 itemindex
= SendMessage(hwnd
, LB_INSERTSTRING
, -1,
1340 (LPARAM
)(LPSTR
)vers_name
);
1341 SendMessage(hwnd
, LB_SETCURSEL
, itemindex
, 0);
1342 SendMessage(hwnd
, LB_SETITEMDATA
, itemindex
,
1343 (LPARAM
)(LPSTR
)strdup(pathname
));
1348 #endif /* USE_OTHER_PYTHON_VERSIONS */
1350 typedef struct _InstalledVersionInfo
{
1351 char prefix
[MAX_PATH
+1]; // sys.prefix directory.
1352 HKEY hkey
; // Is this Python in HKCU or HKLM?
1353 } InstalledVersionInfo
;
1357 * Fill the listbox specified by hwnd with all python versions found
1358 * in the registry. version, if not NULL or empty, is the version
1361 static BOOL
GetPythonVersions(HWND hwnd
, HKEY hkRoot
, LPSTR version
)
1364 char core_version
[80];
1369 if (ERROR_SUCCESS
!= RegOpenKeyEx(hkRoot
,
1370 "Software\\Python\\PythonCore",
1371 0, KEY_READ
, &hKey
))
1373 bufsize
= sizeof(core_version
);
1374 while (ERROR_SUCCESS
== RegEnumKeyEx(hKey
, index
,
1375 core_version
, &bufsize
, NULL
,
1376 NULL
, NULL
, NULL
)) {
1377 char subkey_name
[80], vers_name
[80];
1382 bufsize
= sizeof(core_version
);
1384 if (version
&& *version
&& strcmp(version
, core_version
))
1387 wsprintf(vers_name
, "Python Version %s (found in registry)",
1389 wsprintf(subkey_name
,
1390 "Software\\Python\\PythonCore\\%s\\InstallPath",
1392 if (ERROR_SUCCESS
== RegOpenKeyEx(hkRoot
, subkey_name
, 0, KEY_READ
, &hk
)) {
1393 InstalledVersionInfo
*ivi
=
1394 (InstalledVersionInfo
*)malloc(sizeof(InstalledVersionInfo
));
1395 value_size
= sizeof(ivi
->prefix
);
1397 ERROR_SUCCESS
== RegQueryValueEx(hk
, NULL
, NULL
, NULL
,
1398 ivi
->prefix
, &value_size
)) {
1399 itemindex
= SendMessage(hwnd
, LB_ADDSTRING
, 0,
1400 (LPARAM
)(LPSTR
)vers_name
);
1402 SendMessage(hwnd
, LB_SETITEMDATA
, itemindex
,
1403 (LPARAM
)(LPSTR
)ivi
);
1412 /* Determine if the current user can write to HKEY_LOCAL_MACHINE */
1413 BOOL
HasLocalMachinePrivs()
1417 static char KeyName
[] =
1418 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1420 result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
1430 // Check the root registry key to use - either HKLM or HKCU.
1431 // If Python is installed in HKCU, then our extension also must be installed
1432 // in HKCU - as Python won't be available for other users, we shouldn't either
1433 // (and will fail if we are!)
1434 // If Python is installed in HKLM, then we will also prefer to use HKLM, but
1435 // this may not be possible - so we silently fall back to HKCU.
1437 // We assume hkey_root is already set to where Python itself is installed.
1438 void CheckRootKey(HWND hwnd
)
1440 if (hkey_root
==HKEY_CURRENT_USER
) {
1441 ; // as above, always install ourself in HKCU too.
1442 } else if (hkey_root
==HKEY_LOCAL_MACHINE
) {
1443 // Python in HKLM, but we may or may not have permissions there.
1444 // Open the uninstall key with 'create' permissions - if this fails,
1445 // we don't have permission.
1446 if (!HasLocalMachinePrivs())
1447 hkey_root
= HKEY_CURRENT_USER
;
1449 MessageBox(hwnd
, "Don't know Python's installation type",
1450 "Strange", MB_OK
| MB_ICONSTOP
);
1451 /* Default to wherever they can, but preferring HKLM */
1452 hkey_root
= HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
1456 /* Return the installation scheme depending on Python version number */
1457 SCHEME
*GetScheme(int major
, int minor
)
1461 else if((major
== 2) && (minor
>= 2))
1467 SelectPythonDlgProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1474 SendDlgItemMessage(hwnd
, IDC_BITMAP
, STM_SETIMAGE
,
1475 IMAGE_BITMAP
, (LPARAM
)hBitmap
);
1476 GetPythonVersions(GetDlgItem(hwnd
, IDC_VERSIONS_LIST
),
1477 HKEY_LOCAL_MACHINE
, target_version
);
1478 GetPythonVersions(GetDlgItem(hwnd
, IDC_VERSIONS_LIST
),
1479 HKEY_CURRENT_USER
, target_version
);
1480 { /* select the last entry which is the highest python
1483 count
= SendDlgItemMessage(hwnd
, IDC_VERSIONS_LIST
,
1485 if (count
&& count
!= LB_ERR
)
1486 SendDlgItemMessage(hwnd
, IDC_VERSIONS_LIST
, LB_SETCURSEL
,
1489 /* If a specific Python version is required,
1490 * display a prominent notice showing this fact.
1492 if (target_version
&& target_version
[0]) {
1495 "Python %s is required for this package. "
1496 "Select installation to use:",
1498 SetDlgItemText(hwnd
, IDC_TITLE
, buffer
);
1504 if (target_version
&& target_version
[0]) {
1506 "Python version %s required, which was not found"
1507 " in the registry.", target_version
);
1510 msg
= "No Python installation found in the registry.";
1511 MessageBox(hwnd
, msg
, "Cannot install",
1512 MB_OK
| MB_ICONSTOP
);
1515 goto UpdateInstallDir
;
1519 switch (LOWORD(wParam
)) {
1521 case IDC_OTHERPYTHON:
1522 if (GetOtherPythonVersion(GetDlgItem(hwnd, IDC_VERSIONS_LIST),
1524 goto UpdateInstallDir;
1527 case IDC_VERSIONS_LIST
:
1528 switch (HIWORD(wParam
)) {
1532 PropSheet_SetWizButtons(GetParent(hwnd
),
1533 PSWIZB_BACK
| PSWIZB_NEXT
);
1534 id
= SendDlgItemMessage(hwnd
, IDC_VERSIONS_LIST
,
1535 LB_GETCURSEL
, 0, 0);
1537 PropSheet_SetWizButtons(GetParent(hwnd
),
1539 SetDlgItemText(hwnd
, IDC_PATH
, "");
1540 SetDlgItemText(hwnd
, IDC_INSTALL_PATH
, "");
1541 strcpy(python_dir
, "");
1542 strcpy(pythondll
, "");
1546 InstalledVersionInfo
*ivi
;
1547 PropSheet_SetWizButtons(GetParent(hwnd
),
1548 PSWIZB_BACK
| PSWIZB_NEXT
);
1549 /* Get the python directory */
1550 ivi
= (InstalledVersionInfo
*)
1551 SendDlgItemMessage(hwnd
,
1556 hkey_root
= ivi
->hkey
;
1557 strcpy(python_dir
, ivi
->prefix
);
1558 SetDlgItemText(hwnd
, IDC_PATH
, python_dir
);
1559 /* retrieve the python version and pythondll to use */
1560 result
= SendDlgItemMessage(hwnd
, IDC_VERSIONS_LIST
,
1561 LB_GETTEXTLEN
, (WPARAM
)id
, 0);
1562 pbuf
= (char *)malloc(result
+ 1);
1564 /* guess the name of the python-dll */
1565 SendDlgItemMessage(hwnd
, IDC_VERSIONS_LIST
,
1566 LB_GETTEXT
, (WPARAM
)id
,
1568 result
= sscanf(pbuf
, "Python Version %d.%d",
1569 &py_major
, &py_minor
);
1572 wsprintf(pythondll
, "python%d%d_d.dll",
1573 py_major
, py_minor
);
1575 wsprintf(pythondll
, "python%d%d.dll",
1576 py_major
, py_minor
);
1581 strcpy(pythondll
, "");
1582 /* retrieve the scheme for this version */
1584 char install_path
[_MAX_PATH
];
1585 SCHEME
*scheme
= GetScheme(py_major
, py_minor
);
1586 strcpy(install_path
, python_dir
);
1587 if (install_path
[strlen(install_path
)-1] != '\\')
1588 strcat(install_path
, "\\");
1589 strcat(install_path
, scheme
[0].prefix
);
1590 SetDlgItemText(hwnd
, IDC_INSTALL_PATH
, install_path
);
1599 lpnm
= (LPNMHDR
) lParam
;
1601 switch (lpnm
->code
) {
1604 id
= SendDlgItemMessage(hwnd
, IDC_VERSIONS_LIST
,
1605 LB_GETCURSEL
, 0, 0);
1607 PropSheet_SetWizButtons(GetParent(hwnd
),
1610 PropSheet_SetWizButtons(GetParent(hwnd
),
1611 PSWIZB_BACK
| PSWIZB_NEXT
);
1630 static BOOL
OpenLogfile(char *dir
)
1632 char buffer
[_MAX_PATH
+1];
1637 char subkey_name
[256];
1638 static char KeyName
[] =
1639 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
1640 const char *root_name
= (hkey_root
==HKEY_LOCAL_MACHINE
?
1641 "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
1644 /* Use Create, as the Uninstall subkey may not exist under HKCU.
1645 Use CreateKeyEx, so we can specify a SAM specifying write access
1647 result
= RegCreateKeyEx(hkey_root
,
1652 KEY_CREATE_SUB_KEY
, /* sam */
1653 NULL
, /* security */
1654 &hKey
, /* result key */
1655 NULL
); /* disposition */
1656 if (result
!= ERROR_SUCCESS
) {
1657 if (result
== ERROR_ACCESS_DENIED
) {
1658 /* This should no longer be able to happen - we have already
1659 checked if they have permissions in HKLM, and all users
1660 should have write access to HKCU.
1662 MessageBox(GetFocus(),
1663 "You do not seem to have sufficient access rights\n"
1664 "on this machine to install this software",
1666 MB_OK
| MB_ICONSTOP
);
1669 MessageBox(GetFocus(), KeyName
, "Could not open key", MB_OK
);
1673 sprintf(buffer
, "%s\\%s-wininst.log", dir
, meta_name
);
1674 logfile
= fopen(buffer
, "a");
1676 now
= localtime(<ime
);
1677 strftime(buffer
, sizeof(buffer
),
1678 "*** Installation started %Y/%m/%d %H:%M ***\n",
1680 fprintf(logfile
, buffer
);
1681 fprintf(logfile
, "Source: %s\n", modulename
);
1683 /* Root key must be first entry processed by uninstaller. */
1684 fprintf(logfile
, "999 Root Key: %s\n", root_name
);
1686 sprintf(subkey_name
, "%s-py%d.%d", meta_name
, py_major
, py_minor
);
1688 result
= RegCreateKeyEx(hKey
, subkey_name
,
1695 if (result
!= ERROR_SUCCESS
)
1696 MessageBox(GetFocus(), subkey_name
, "Could not create key", MB_OK
);
1700 if (disposition
== REG_CREATED_NEW_KEY
)
1701 fprintf(logfile
, "020 Reg DB Key: [%s]%s\n", KeyName
, subkey_name
);
1703 sprintf(buffer
, "Python %d.%d %s", py_major
, py_minor
, title
);
1705 result
= RegSetValueEx(hSubkey
, "DisplayName",
1711 if (result
!= ERROR_SUCCESS
)
1712 MessageBox(GetFocus(), buffer
, "Could not set key value", MB_OK
);
1714 fprintf(logfile
, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1715 KeyName
, subkey_name
, "DisplayName", buffer
);
1719 sprintf(buffer
, "%s\\Remove%s.exe", dir
, meta_name
);
1720 fp
= fopen(buffer
, "wb");
1721 fwrite(arc_data
, exe_size
, 1, fp
);
1724 sprintf(buffer
, "\"%s\\Remove%s.exe\" -u \"%s\\%s-wininst.log\"",
1725 dir
, meta_name
, dir
, meta_name
);
1727 result
= RegSetValueEx(hSubkey
, "UninstallString",
1733 if (result
!= ERROR_SUCCESS
)
1734 MessageBox(GetFocus(), buffer
, "Could not set key value", MB_OK
);
1736 fprintf(logfile
, "040 Reg DB Value: [%s\\%s]%s=%s\n",
1737 KeyName
, subkey_name
, "UninstallString", buffer
);
1742 static void CloseLogfile(void)
1744 char buffer
[_MAX_PATH
+1];
1749 now
= localtime(<ime
);
1750 strftime(buffer
, sizeof(buffer
),
1751 "*** Installation finished %Y/%m/%d %H:%M ***\n",
1753 fprintf(logfile
, buffer
);
1759 InstallFilesDlgProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1768 SendDlgItemMessage(hwnd
, IDC_BITMAP
, STM_SETIMAGE
,
1769 IMAGE_BITMAP
, (LPARAM
)hBitmap
);
1771 "Click Next to begin the installation of %s. "
1772 "If you want to review or change any of your "
1773 " installation settings, click Back. "
1774 "Click Cancel to exit the wizard.",
1776 SetDlgItemText(hwnd
, IDC_TITLE
, Buffer
);
1777 SetDlgItemText(hwnd
, IDC_INFO
, "Ready to install");
1781 SendDlgItemMessage(hwnd
, IDC_PROGRESS
, PBM_SETRANGE
, 0, lParam
);
1786 SendDlgItemMessage(hwnd
, IDC_PROGRESS
, PBM_SETPOS
, wParam
,
1788 SetDlgItemText(hwnd
, IDC_INFO
, (LPSTR
)lParam
);
1793 lpnm
= (LPNMHDR
) lParam
;
1795 switch (lpnm
->code
) {
1797 PropSheet_SetWizButtons(GetParent(hwnd
),
1798 PSWIZB_BACK
| PSWIZB_NEXT
);
1805 /* Handle a Next button click here */
1809 /* Disable the buttons while we work. Sending CANCELTOCLOSE has
1810 the effect of disabling the cancel button, which is a) as we
1811 do everything synchronously we can't cancel, and b) the next
1812 step is 'finished', when it is too late to cancel anyway.
1813 The next step being 'Finished' means we also don't need to
1814 restore the button state back */
1815 PropSheet_SetWizButtons(GetParent(hwnd
), 0);
1816 SendMessage(GetParent(hwnd
), PSM_CANCELTOCLOSE
, 0, 0);
1817 /* Make sure the installation directory name ends in a */
1819 if (python_dir
[strlen(python_dir
)-1] != '\\')
1820 strcat(python_dir
, "\\");
1821 /* Strip the trailing backslash again */
1822 python_dir
[strlen(python_dir
)-1] = '\0';
1826 if (!OpenLogfile(python_dir
))
1830 * The scheme we have to use depends on the Python version...
1831 if sys.version < "2.2":
1835 'headers': '$base/Include/$dist_name',
1836 'scripts': '$base/Scripts',
1841 'purelib': '$base/Lib/site-packages',
1842 'platlib': '$base/Lib/site-packages',
1843 'headers': '$base/Include/$dist_name',
1844 'scripts': '$base/Scripts',
1848 scheme
= GetScheme(py_major
, py_minor
);
1849 /* Run the pre-install script. */
1850 if (pre_install_script
&& *pre_install_script
) {
1851 SetDlgItemText (hwnd
, IDC_TITLE
,
1852 "Running pre-installation script");
1853 run_simple_script(pre_install_script
);
1858 /* Extract all files from the archive */
1859 SetDlgItemText(hwnd
, IDC_TITLE
, "Installing files...");
1860 if (!unzip_archive (scheme
,
1861 python_dir
, arc_data
,
1863 set_failure_reason("Failed to unzip installation files");
1864 /* Compile the py-files */
1865 if (success
&& pyc_compile
) {
1868 SetDlgItemText(hwnd
, IDC_TITLE
,
1869 "Compiling files to .pyc...");
1871 SetDlgItemText(hDialog
, IDC_INFO
, "Loading python...");
1872 hPython
= LoadPythonDll(pythondll
);
1874 errors
= compile_filelist(hPython
, FALSE
);
1875 FreeLibrary(hPython
);
1877 /* Compilation errors are intentionally ignored:
1878 * Python2.0 contains a bug which will result
1879 * in sys.path containing garbage under certain
1880 * circumstances, and an error message will only
1884 if (success
&& pyo_compile
) {
1887 SetDlgItemText(hwnd
, IDC_TITLE
,
1888 "Compiling files to .pyo...");
1890 SetDlgItemText(hDialog
, IDC_INFO
, "Loading python...");
1891 hPython
= LoadPythonDll(pythondll
);
1893 errors
= compile_filelist(hPython
, TRUE
);
1894 FreeLibrary(hPython
);
1896 /* Errors ignored: see above */
1914 FinishedDlgProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1921 SendDlgItemMessage(hwnd
, IDC_BITMAP
, STM_SETIMAGE
,
1922 IMAGE_BITMAP
, (LPARAM
)hBitmap
);
1924 SetDlgItemText(hwnd
, IDC_INFO
, get_failure_reason());
1926 /* async delay: will show the dialog box completely before
1927 the install_script is started */
1928 PostMessage(hwnd
, WM_USER
, 0, 0L);
1933 if (success
&& install_script
&& install_script
[0]) {
1934 char fname
[MAX_PATH
];
1942 char *argv
[3] = {NULL
, "-install", NULL
};
1944 SetDlgItemText(hwnd
, IDC_TITLE
,
1945 "Please wait while running postinstall script...");
1946 strcpy(fname
, python_dir
);
1947 strcat(fname
, "\\Scripts\\");
1948 strcat(fname
, install_script
);
1951 fprintf(logfile
, "300 Run Script: [%s]%s\n", pythondll
, fname
);
1953 tempname
= tempnam(NULL
, NULL
);
1955 if (!freopen(tempname
, "a", stderr
))
1956 MessageBox(GetFocus(), "freopen stderr", NULL
, MB_OK
);
1957 if (!freopen(tempname
, "a", stdout
))
1958 MessageBox(GetFocus(), "freopen stdout", NULL
, MB_OK
);
1960 if (0 != setvbuf(stdout, NULL, _IONBF, 0))
1961 MessageBox(GetFocus(), "setvbuf stdout", NULL, MB_OK);
1963 hCursor
= SetCursor(LoadCursor(NULL
, IDC_WAIT
));
1967 hPython
= LoadPythonDll(pythondll
);
1970 result
= run_installscript(hPython
, fname
, 2, argv
);
1972 fprintf(stderr
, "*** run_installscript: internal error 0x%X ***\n", result
);
1974 FreeLibrary(hPython
);
1976 fprintf(stderr
, "*** Could not load Python ***");
1983 fp
= fopen(tempname
, "rb");
1984 n
= fread(buffer
, 1, sizeof(buffer
), fp
);
1990 SetDlgItemText(hwnd
, IDC_INFO
, buffer
);
1991 SetDlgItemText(hwnd
, IDC_TITLE
,
1992 "Postinstall script finished.\n"
1993 "Click the Finish button to exit the Setup wizard.");
2002 lpnm
= (LPNMHDR
) lParam
;
2004 switch (lpnm
->code
) {
2005 case PSN_SETACTIVE
: /* Enable the Finish button */
2006 PropSheet_SetWizButtons(GetParent(hwnd
), PSWIZB_FINISH
);
2025 void RunWizard(HWND hwnd
)
2027 PROPSHEETPAGE psp
= {0};
2028 HPROPSHEETPAGE ahpsp
[4] = {0};
2029 PROPSHEETHEADER psh
= {0};
2031 /* Display module information */
2032 psp
.dwSize
= sizeof(psp
);
2033 psp
.dwFlags
= PSP_DEFAULT
|PSP_HIDEHEADER
;
2034 psp
.hInstance
= GetModuleHandle (NULL
);
2036 psp
.pfnDlgProc
= IntroDlgProc
;
2037 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_INTRO
);
2039 ahpsp
[0] = CreatePropertySheetPage(&psp
);
2041 /* Select python version to use */
2042 psp
.dwFlags
= PSP_DEFAULT
|PSP_HIDEHEADER
;
2043 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SELECTPYTHON
);
2044 psp
.pfnDlgProc
= SelectPythonDlgProc
;
2046 ahpsp
[1] = CreatePropertySheetPage(&psp
);
2048 /* Install the files */
2049 psp
.dwFlags
= PSP_DEFAULT
|PSP_HIDEHEADER
;
2050 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_INSTALLFILES
);
2051 psp
.pfnDlgProc
= InstallFilesDlgProc
;
2053 ahpsp
[2] = CreatePropertySheetPage(&psp
);
2055 /* Show success or failure */
2056 psp
.dwFlags
= PSP_DEFAULT
|PSP_HIDEHEADER
;
2057 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_FINISHED
);
2058 psp
.pfnDlgProc
= FinishedDlgProc
;
2060 ahpsp
[3] = CreatePropertySheetPage(&psp
);
2062 /* Create the property sheet */
2063 psh
.dwSize
= sizeof(psh
);
2064 psh
.hInstance
= GetModuleHandle(NULL
);
2065 psh
.hwndParent
= hwnd
;
2067 psh
.dwFlags
= PSH_WIZARD
/*97*//*|PSH_WATERMARK|PSH_HEADER*/;
2068 psh
.pszbmWatermark
= NULL
;
2069 psh
.pszbmHeader
= NULL
;
2073 PropertySheet(&psh
);
2078 char ini_buffer
[4096];
2080 /* Read installation information */
2081 GetPrivateProfileString("Setup", "title", "", ini_buffer
,
2082 sizeof(ini_buffer
), ini_file
);
2083 unescape(title
, ini_buffer
, sizeof(title
));
2085 GetPrivateProfileString("Setup", "info", "", ini_buffer
,
2086 sizeof(ini_buffer
), ini_file
);
2087 unescape(info
, ini_buffer
, sizeof(info
));
2089 GetPrivateProfileString("Setup", "build_info", "", build_info
,
2090 sizeof(build_info
), ini_file
);
2092 pyc_compile
= GetPrivateProfileInt("Setup", "target_compile", 1,
2094 pyo_compile
= GetPrivateProfileInt("Setup", "target_optimize", 1,
2097 GetPrivateProfileString("Setup", "target_version", "",
2098 target_version
, sizeof(target_version
),
2101 GetPrivateProfileString("metadata", "name", "",
2102 meta_name
, sizeof(meta_name
),
2105 GetPrivateProfileString("Setup", "install_script", "",
2106 install_script
, sizeof(install_script
),
2110 hwndMain
= CreateBackground(title
);
2112 RunWizard(hwndMain
);
2115 UnmapViewOfFile(arc_data
);
2117 DeleteFile(ini_file
);
2120 DeleteObject(hBitmap
);
2125 /*********************** uninstall section ******************************/
2127 static int compare(const void *p1
, const void *p2
)
2129 return strcmp(*(char **)p2
, *(char **)p1
);
2133 * Commit suicide (remove the uninstaller itself).
2135 * Create a batch file to first remove the uninstaller
2136 * (will succeed after it has finished), then the batch file itself.
2138 * This technique has been demonstrated by Jeff Richter,
2141 void remove_exe(void)
2143 char exename
[_MAX_PATH
];
2144 char batname
[_MAX_PATH
];
2147 PROCESS_INFORMATION pi
;
2149 GetModuleFileName(NULL
, exename
, sizeof(exename
));
2150 sprintf(batname
, "%s.bat", exename
);
2151 fp
= fopen(batname
, "w");
2152 fprintf(fp
, ":Repeat\n");
2153 fprintf(fp
, "del \"%s\"\n", exename
);
2154 fprintf(fp
, "if exist \"%s\" goto Repeat\n", exename
);
2155 fprintf(fp
, "del \"%s\"\n", batname
);
2158 ZeroMemory(&si
, sizeof(si
));
2160 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2161 si
.wShowWindow
= SW_HIDE
;
2162 if (CreateProcess(NULL
,
2167 CREATE_SUSPENDED
| IDLE_PRIORITY_CLASS
,
2172 SetThreadPriority(pi
.hThread
, THREAD_PRIORITY_IDLE
);
2173 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
2174 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
);
2175 CloseHandle(pi
.hProcess
);
2176 ResumeThread(pi
.hThread
);
2177 CloseHandle(pi
.hThread
);
2181 void DeleteRegistryKey(char *string
)
2190 line
= strdup(string
); /* so we can change it */
2192 keyname
= strchr(line
, '[');
2197 subkeyname
= strchr(keyname
, ']');
2201 delim
= strchr(subkeyname
, '\n');
2205 result
= RegOpenKeyEx(hkey_root
,
2211 if (result
!= ERROR_SUCCESS
)
2212 MessageBox(GetFocus(), string
, "Could not open key", MB_OK
);
2214 result
= RegDeleteKey(hKey
, subkeyname
);
2215 if (result
!= ERROR_SUCCESS
&& result
!= ERROR_FILE_NOT_FOUND
)
2216 MessageBox(GetFocus(), string
, "Could not delete key", MB_OK
);
2222 void DeleteRegistryValue(char *string
)
2231 line
= strdup(string
); /* so we can change it */
2233 /* Format is 'Reg DB Value: [key]name=value' */
2234 keyname
= strchr(line
, '[');
2238 valuename
= strchr(keyname
, ']');
2241 *valuename
++ = '\0';
2242 value
= strchr(valuename
, '=');
2248 result
= RegOpenKeyEx(hkey_root
,
2253 if (result
!= ERROR_SUCCESS
)
2254 MessageBox(GetFocus(), string
, "Could not open key", MB_OK
);
2256 result
= RegDeleteValue(hKey
, valuename
);
2257 if (result
!= ERROR_SUCCESS
&& result
!= ERROR_FILE_NOT_FOUND
)
2258 MessageBox(GetFocus(), string
, "Could not delete value", MB_OK
);
2264 BOOL
MyDeleteFile(char *line
)
2266 char *pathname
= strchr(line
, ':');
2270 while (isspace(*pathname
))
2272 return DeleteFile(pathname
);
2275 BOOL
MyRemoveDirectory(char *line
)
2277 char *pathname
= strchr(line
, ':');
2281 while (isspace(*pathname
))
2283 return RemoveDirectory(pathname
);
2286 BOOL
Run_RemoveScript(char *line
)
2290 static char lastscript
[MAX_PATH
];
2292 /* Format is 'Run Scripts: [pythondll]scriptname' */
2293 /* XXX Currently, pythondll carries no path!!! */
2294 dllname
= strchr(line
, '[');
2298 scriptname
= strchr(dllname
, ']');
2301 *scriptname
++ = '\0';
2302 /* this function may be called more than one time with the same
2303 script, only run it one time */
2304 if (strcmp(lastscript
, scriptname
)) {
2306 char *argv
[3] = {NULL
, "-remove", NULL
};
2312 argv
[0] = scriptname
;
2314 tempname
= tempnam(NULL
, NULL
);
2316 if (!freopen(tempname
, "a", stderr
))
2317 MessageBox(GetFocus(), "freopen stderr", NULL
, MB_OK
);
2318 if (!freopen(tempname
, "a", stdout
))
2319 MessageBox(GetFocus(), "freopen stdout", NULL
, MB_OK
);
2321 hPython
= LoadLibrary(dllname
);
2323 if (0x80000000 == run_installscript(hPython
, scriptname
, 2, argv
))
2324 fprintf(stderr
, "*** Could not load Python ***");
2325 FreeLibrary(hPython
);
2333 fp
= fopen(tempname
, "rb");
2334 n
= fread(buffer
, 1, sizeof(buffer
), fp
);
2340 MessageBox(GetFocus(), buffer
, "uninstall-script", MB_OK
);
2342 strcpy(lastscript
, scriptname
);
2347 int DoUninstall(int argc
, char **argv
)
2358 int lines_buffer_size
= 10;
2362 "Wrong number of args",
2365 return 1; /* Error */
2367 if (strcmp(argv
[1], "-u")) {
2372 return 1; /* Error */
2375 logfile
= fopen(argv
[2], "r");
2378 "could not open logfile",
2381 return 1; /* Error */
2384 lines
= (char **)malloc(sizeof(char *) * lines_buffer_size
);
2386 return SystemError(0, "Out of memory");
2388 /* Read the whole logfile, realloacting the buffer */
2389 while (fgets(buffer
, sizeof(buffer
), logfile
)) {
2390 int len
= strlen(buffer
);
2391 /* remove trailing white space */
2392 while (isspace(buffer
[len
-1]))
2395 lines
[nLines
++] = strdup(buffer
);
2396 if (nLines
>= lines_buffer_size
) {
2397 lines_buffer_size
+= 10;
2398 lines
= (char **)realloc(lines
,
2399 sizeof(char *) * lines_buffer_size
);
2401 return SystemError(0, "Out of memory");
2406 /* Sort all the lines, so that highest 3-digit codes are first */
2407 qsort(&lines
[0], nLines
, sizeof(char *),
2410 if (IDYES
!= MessageBox(NULL
,
2411 "Are you sure you want to remove\n"
2412 "this package from your computer?",
2414 MB_YESNO
| MB_ICONQUESTION
))
2417 hkey_root
= HKEY_LOCAL_MACHINE
;
2419 for (i
= 0; i
< nLines
; ++i
) {
2420 /* Ignore duplicate lines */
2421 if (strcmp(cp
, lines
[i
])) {
2424 /* Parse the lines */
2425 if (2 == sscanf(cp
, "%d Root Key: %s", &ign
, &buffer
)) {
2426 if (strcmp(buffer
, "HKEY_CURRENT_USER")==0)
2427 hkey_root
= HKEY_CURRENT_USER
;
2429 // HKLM - check they have permissions.
2430 if (!HasLocalMachinePrivs()) {
2431 MessageBox(GetFocus(),
2432 "You do not seem to have sufficient access rights\n"
2433 "on this machine to uninstall this software",
2435 MB_OK
| MB_ICONSTOP
);
2436 return 1; /* Error */
2439 } else if (2 == sscanf(cp
, "%d Made Dir: %s", &ign
, &buffer
)) {
2440 if (MyRemoveDirectory(cp
))
2443 int code
= GetLastError();
2444 if (code
!= 2 && code
!= 3) { /* file or path not found */
2448 } else if (2 == sscanf(cp
, "%d File Copy: %s", &ign
, &buffer
)) {
2449 if (MyDeleteFile(cp
))
2452 int code
= GetLastError();
2453 if (code
!= 2 && code
!= 3) { /* file or path not found */
2457 } else if (2 == sscanf(cp
, "%d File Overwrite: %s", &ign
, &buffer
)) {
2458 if (MyDeleteFile(cp
))
2461 int code
= GetLastError();
2462 if (code
!= 2 && code
!= 3) { /* file or path not found */
2466 } else if (2 == sscanf(cp
, "%d Reg DB Key: %s", &ign
, &buffer
)) {
2467 DeleteRegistryKey(cp
);
2468 } else if (2 == sscanf(cp
, "%d Reg DB Value: %s", &ign
, &buffer
)) {
2469 DeleteRegistryValue(cp
);
2470 } else if (2 == sscanf(cp
, "%d Run Script: %s", &ign
, &buffer
)) {
2471 Run_RemoveScript(cp
);
2476 if (DeleteFile(argv
[2])) {
2480 SystemError(GetLastError(), argv
[2]);
2484 "%d files and %d directories removed\n"
2485 "%d files or directories could not be removed",
2486 nFiles
, nDirs
, nErrors
);
2488 wsprintf(buffer
, "%d files and %d directories removed",
2490 MessageBox(NULL
, buffer
, "Uninstall Finished!",
2491 MB_OK
| MB_ICONINFORMATION
);
2496 int WINAPI
WinMain(HINSTANCE hInst
, HINSTANCE hPrevInst
,
2497 LPSTR lpszCmdLine
, INT nCmdShow
)
2500 extern char **__argv
;
2503 GetModuleFileName(NULL
, modulename
, sizeof(modulename
));
2505 /* Map the executable file to memory */
2506 arc_data
= MapExistingFile(modulename
, &arc_size
);
2508 SystemError(GetLastError(), "Could not open archive");
2512 /* OK. So this program can act as installer (self-extracting
2513 * zip-file, or as uninstaller when started with '-u logfile'
2514 * command line flags.
2516 * The installer is usually started without command line flags,
2517 * and the uninstaller is usually started with the '-u logfile'
2518 * flag. What to do if some innocent user double-clicks the
2520 * The following implements a defensive strategy...
2523 /* Try to extract the configuration data into a temporary file */
2524 if (ExtractInstallData(arc_data
, arc_size
, &exe_size
,
2525 &ini_file
, &pre_install_script
))
2528 if (!ini_file
&& __argc
> 1) {
2529 return DoUninstall(__argc
, __argv
);
2533 basename
= strrchr(modulename
, '\\');
2537 /* Last guess about the purpose of this program */
2538 if (basename
&& (0 == strncmp(basename
, "Remove", 6)))
2539 SystemError(0, "This program is normally started by windows");
2541 SystemError(0, "Setup program invalid or damaged");