blob: b015abd59e66a103cd490e582d2ecf551b264714 [file] [log] [blame]
Steve Dower0e4ad882018-12-10 19:58:52 -08001/* Main program when embedded in a UWP application on Windows */
2
3#include "Python.h"
4#include <string.h>
5
6#define WIN32_LEAN_AND_MEAN
7#include <Windows.h>
8#include <shellapi.h>
9
10#ifdef PYTHON_UWP_SUPPORTED
11#include <winrt\Windows.ApplicationModel.h>
12#include <winrt\Windows.Storage.h>
13#else
14#include <string>
15#endif
16
17#ifdef PYTHONW
18#ifdef _DEBUG
19const wchar_t *PROGNAME = L"pythonw_d.exe";
20#else
21const wchar_t *PROGNAME = L"pythonw.exe";
22#endif
23#else
24#ifdef _DEBUG
25const wchar_t *PROGNAME = L"python_d.exe";
26#else
27const wchar_t *PROGNAME = L"python.exe";
28#endif
29#endif
30
31static void
32set_user_base()
33{
34#ifdef PYTHON_UWP_SUPPORTED
35 wchar_t envBuffer[2048];
36 try {
37 const auto appData = winrt::Windows::Storage::ApplicationData::Current();
38 if (appData) {
39 const auto localCache = appData.LocalCacheFolder();
40 if (localCache) {
41 auto path = localCache.Path();
42 if (!path.empty() &&
43 !wcscpy_s(envBuffer, path.c_str()) &&
44 !wcscat_s(envBuffer, L"\\local-packages")
45 ) {
46 _wputenv_s(L"PYTHONUSERBASE", envBuffer);
47 }
48 }
49 }
50 } catch (...) {
51 }
52#endif
53}
54
55static const wchar_t *
56get_argv0(const wchar_t *argv0)
57{
58#ifdef PYTHON_UWP_SUPPORTED
59 winrt::hstring installPath;
60#else
61 std::wstring installPath;
62#endif
63 const wchar_t *launcherPath;
64 wchar_t *buffer;
65 size_t len;
66
67 launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
68 if (launcherPath && launcherPath[0]) {
69 len = wcslen(launcherPath) + 1;
70 buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
71 if (!buffer) {
72 Py_FatalError("out of memory");
73 return NULL;
74 }
75 if (wcscpy_s(buffer, len, launcherPath)) {
76 Py_FatalError("failed to copy to buffer");
77 return NULL;
78 }
79 return buffer;
80 }
81
82#ifdef PYTHON_UWP_SUPPORTED
83 try {
84 const auto package = winrt::Windows::ApplicationModel::Package::Current();
85 if (package) {
86 const auto install = package.InstalledLocation();
87 if (install) {
88 installPath = install.Path();
89 }
90 }
91 }
92 catch (...) {
93 }
94#endif
95
96 if (!installPath.empty()) {
97 len = installPath.size() + wcslen(PROGNAME) + 2;
98 } else {
99 len = wcslen(argv0) + wcslen(PROGNAME) + 1;
100 }
101
102 buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
103 if (!buffer) {
104 Py_FatalError("out of memory");
105 return NULL;
106 }
107
108 if (!installPath.empty()) {
109 if (wcscpy_s(buffer, len, installPath.c_str())) {
110 Py_FatalError("failed to copy to buffer");
111 return NULL;
112 }
113 if (wcscat_s(buffer, len, L"\\")) {
114 Py_FatalError("failed to concatenate backslash");
115 return NULL;
116 }
117 } else {
118 if (wcscpy_s(buffer, len, argv0)) {
119 Py_FatalError("failed to copy argv[0]");
120 return NULL;
121 }
122
123 wchar_t *name = wcsrchr(buffer, L'\\');
124 if (name) {
125 name[1] = L'\0';
126 } else {
127 buffer[0] = L'\0';
128 }
129 }
130
131 if (wcscat_s(buffer, len, PROGNAME)) {
132 Py_FatalError("failed to concatenate program name");
133 return NULL;
134 }
135
136 return buffer;
137}
138
139static wchar_t *
140get_process_name()
141{
142 DWORD bufferLen = MAX_PATH;
143 DWORD len = bufferLen;
144 wchar_t *r = NULL;
145
146 while (!r) {
147 r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
148 if (!r) {
149 Py_FatalError("out of memory");
150 return NULL;
151 }
152 len = GetModuleFileNameW(NULL, r, bufferLen);
153 if (len == 0) {
154 free((void *)r);
155 return NULL;
156 } else if (len == bufferLen &&
157 GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
158 free(r);
159 r = NULL;
160 bufferLen *= 2;
161 }
162 }
163
164 return r;
165}
166
167int
168wmain(int argc, wchar_t **argv)
169{
170 const wchar_t **new_argv;
171 int new_argc;
172 const wchar_t *exeName;
173
174 new_argc = argc;
175 new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
176 if (new_argv == NULL) {
177 Py_FatalError("out of memory");
178 return -1;
179 }
180
181 exeName = get_process_name();
182
183 new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
184 for (int i = 1; i < argc; ++i) {
185 new_argv[i] = argv[i];
186 }
187
188 set_user_base();
189
190 if (exeName) {
191 const wchar_t *p = wcsrchr(exeName, L'\\');
192 if (p) {
193 const wchar_t *moduleName = NULL;
194 if (*p++ == L'\\') {
195 if (wcsnicmp(p, L"pip", 3) == 0) {
196 moduleName = L"pip";
197 _wputenv_s(L"PIP_USER", L"true");
198 }
199 else if (wcsnicmp(p, L"idle", 4) == 0) {
200 moduleName = L"idlelib";
201 }
202 }
203
204 if (moduleName) {
205 new_argc += 2;
206 for (int i = argc; i >= 1; --i) {
207 new_argv[i + 2] = new_argv[i];
208 }
209 new_argv[1] = L"-m";
210 new_argv[2] = moduleName;
211 }
212 }
213 }
214
215 /* Override program_full_path from here so that
216 sys.executable is set correctly. */
217 _Py_SetProgramFullPath(new_argv[0]);
218
219 int result = Py_Main(new_argc, (wchar_t **)new_argv);
220
221 free((void *)exeName);
222 free((void *)new_argv);
223
224 return result;
225}
226
227#ifdef PYTHONW
228
229int WINAPI wWinMain(
230 HINSTANCE hInstance, /* handle to current instance */
231 HINSTANCE hPrevInstance, /* handle to previous instance */
232 LPWSTR lpCmdLine, /* pointer to command line */
233 int nCmdShow /* show state of window */
234)
235{
236 return wmain(__argc, __wargv);
237}
238
239#endif