PageRenderTime 34ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/PC/bdist_wininst/install.c

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