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