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