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