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