##// END OF EJS Templates
exewrapper: add .dll to LoadLibrary() argument...
Gregory Szorc -
r29019:210bb28c stable
parent child Browse files
Show More
@@ -1,174 +1,175 b''
1 1 /*
2 2 exewrapper.c - wrapper for calling a python script on Windows
3 3
4 4 Copyright 2012 Adrian Buehlmann <adrian@cadifra.com> and others
5 5
6 6 This software may be used and distributed according to the terms of the
7 7 GNU General Public License version 2 or any later version.
8 8 */
9 9
10 10 #include <stdio.h>
11 11 #include <windows.h>
12 12
13 13 #include "hgpythonlib.h"
14 14
15 15 #ifdef __GNUC__
16 16 int strcat_s(char *d, size_t n, const char *s)
17 17 {
18 18 return !strncat(d, s, n);
19 19 }
20 20 int strcpy_s(char *d, size_t n, const char *s)
21 21 {
22 22 return !strncpy(d, s, n);
23 23 }
24 24 #endif
25 25
26 26
27 27 static char pyscript[MAX_PATH + 10];
28 28 static char pyhome[MAX_PATH + 10];
29 29 static char envpyhome[MAX_PATH + 10];
30 30 static char pydllfile[MAX_PATH + 10];
31 31
32 32 int main(int argc, char *argv[])
33 33 {
34 34 char *p;
35 35 int ret;
36 36 int i;
37 37 int n;
38 38 char **pyargv;
39 39 WIN32_FIND_DATA fdata;
40 40 HANDLE hfind;
41 41 const char *err;
42 42 HMODULE pydll;
43 43 void (__cdecl *Py_SetPythonHome)(char *home);
44 44 int (__cdecl *Py_Main)(int argc, char *argv[]);
45 45
46 46 if (GetModuleFileName(NULL, pyscript, sizeof(pyscript)) == 0)
47 47 {
48 48 err = "GetModuleFileName failed";
49 49 goto bail;
50 50 }
51 51
52 52 p = strrchr(pyscript, '.');
53 53 if (p == NULL) {
54 54 err = "malformed module filename";
55 55 goto bail;
56 56 }
57 57 *p = 0; /* cut trailing ".exe" */
58 58 strcpy_s(pyhome, sizeof(pyhome), pyscript);
59 59
60 60 hfind = FindFirstFile(pyscript, &fdata);
61 61 if (hfind != INVALID_HANDLE_VALUE) {
62 62 /* pyscript exists, close handle */
63 63 FindClose(hfind);
64 64 } else {
65 65 /* file pyscript isn't there, take <pyscript>exe.py */
66 66 strcat_s(pyscript, sizeof(pyscript), "exe.py");
67 67 }
68 68
69 69 pydll = NULL;
70 70 /*
71 71 We first check, that environment variable PYTHONHOME is *not* set.
72 72 This just mimicks the behavior of the regular python.exe, which uses
73 73 PYTHONHOME to find its installation directory (if it has been set).
74 74 Note: Users of HackableMercurial are expected to *not* set PYTHONHOME!
75 75 */
76 76 if (GetEnvironmentVariable("PYTHONHOME", envpyhome,
77 77 sizeof(envpyhome)) == 0)
78 78 {
79 79 /*
80 80 Environment var PYTHONHOME is *not* set. Let's see if we are
81 81 running inside a HackableMercurial.
82 82 */
83 83
84 84 p = strrchr(pyhome, '\\');
85 85 if (p == NULL) {
86 86 err = "can't find backslash in module filename";
87 87 goto bail;
88 88 }
89 89 *p = 0; /* cut at directory */
90 90
91 91 /* check for private Python of HackableMercurial */
92 92 strcat_s(pyhome, sizeof(pyhome), "\\hg-python");
93 93
94 94 hfind = FindFirstFile(pyhome, &fdata);
95 95 if (hfind != INVALID_HANDLE_VALUE) {
96 96 /* path pyhome exists, let's use it */
97 97 FindClose(hfind);
98 98 strcpy_s(pydllfile, sizeof(pydllfile), pyhome);
99 strcat_s(pydllfile, sizeof(pydllfile), "\\" HGPYTHONLIB);
99 strcat_s(pydllfile, sizeof(pydllfile),
100 "\\" HGPYTHONLIB ".dll");
100 101 pydll = LoadLibrary(pydllfile);
101 102 if (pydll == NULL) {
102 103 err = "failed to load private Python DLL "
103 104 HGPYTHONLIB ".dll";
104 105 goto bail;
105 106 }
106 107 Py_SetPythonHome = (void*)GetProcAddress(pydll,
107 108 "Py_SetPythonHome");
108 109 if (Py_SetPythonHome == NULL) {
109 110 err = "failed to get Py_SetPythonHome";
110 111 goto bail;
111 112 }
112 113 Py_SetPythonHome(pyhome);
113 114 }
114 115 }
115 116
116 117 if (pydll == NULL) {
117 pydll = LoadLibrary(HGPYTHONLIB);
118 pydll = LoadLibrary(HGPYTHONLIB ".dll");
118 119 if (pydll == NULL) {
119 120 err = "failed to load Python DLL " HGPYTHONLIB ".dll";
120 121 goto bail;
121 122 }
122 123 }
123 124
124 125 Py_Main = (void*)GetProcAddress(pydll, "Py_Main");
125 126 if (Py_Main == NULL) {
126 127 err = "failed to get Py_Main";
127 128 goto bail;
128 129 }
129 130
130 131 /*
131 132 Only add the pyscript to the args, if it's not already there. It may
132 133 already be there, if the script spawned a child process of itself, in
133 134 the same way as it got called, that is, with the pyscript already in
134 135 place. So we optionally accept the pyscript as the first argument
135 136 (argv[1]), letting our exe taking the role of the python interpreter.
136 137 */
137 138 if (argc >= 2 && strcmp(argv[1], pyscript) == 0) {
138 139 /*
139 140 pyscript is already in the args, so there is no need to copy
140 141 the args and we can directly call the python interpreter with
141 142 the original args.
142 143 */
143 144 return Py_Main(argc, argv);
144 145 }
145 146
146 147 /*
147 148 Start assembling the args for the Python interpreter call. We put the
148 149 name of our exe (argv[0]) in the position where the python.exe
149 150 canonically is, and insert the pyscript next.
150 151 */
151 152 pyargv = malloc((argc + 5) * sizeof(char*));
152 153 if (pyargv == NULL) {
153 154 err = "not enough memory";
154 155 goto bail;
155 156 }
156 157 n = 0;
157 158 pyargv[n++] = argv[0];
158 159 pyargv[n++] = pyscript;
159 160
160 161 /* copy remaining args from the command line */
161 162 for (i = 1; i < argc; i++)
162 163 pyargv[n++] = argv[i];
163 164 /* argv[argc] is guaranteed to be NULL, so we forward that guarantee */
164 165 pyargv[n] = NULL;
165 166
166 167 ret = Py_Main(n, pyargv); /* The Python interpreter call */
167 168
168 169 free(pyargv);
169 170 return ret;
170 171
171 172 bail:
172 173 fprintf(stderr, "abort: %s\n", err);
173 174 return 255;
174 175 }
General Comments 0
You need to be logged in to leave comments. Login now