1 /* 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 <shlobj.h>
10
11 #include <string>
12
13 #include <winrt\Windows.ApplicationModel.h>
14 #include <winrt\Windows.Storage.h>
15
16 #ifdef PYTHONW
17 #ifdef _DEBUG
18 const wchar_t *PROGNAME = L"pythonw_d.exe";
19 #else
20 const wchar_t *PROGNAME = L"pythonw.exe";
21 #endif
22 #else
23 #ifdef _DEBUG
24 const wchar_t *PROGNAME = L"python_d.exe";
25 #else
26 const wchar_t *PROGNAME = L"python.exe";
27 #endif
28 #endif
29
30 static std::wstring
get_user_base()31 get_user_base()
32 {
33 try {
34 const auto appData = winrt::Windows::Storage::ApplicationData::Current();
35 if (appData) {
36 const auto localCache = appData.LocalCacheFolder();
37 if (localCache) {
38 auto path = localCache.Path();
39 if (!path.empty()) {
40 return std::wstring(path) + L"\\local-packages";
41 }
42 }
43 }
44 } catch (...) {
45 }
46 return std::wstring();
47 }
48
49 static std::wstring
get_package_family()50 get_package_family()
51 {
52 try {
53 const auto package = winrt::Windows::ApplicationModel::Package::Current();
54 if (package) {
55 const auto id = package.Id();
56 if (id) {
57 return std::wstring(id.FamilyName());
58 }
59 }
60 }
61 catch (...) {
62 }
63
64 return std::wstring();
65 }
66
67 static std::wstring
get_package_home()68 get_package_home()
69 {
70 try {
71 const auto package = winrt::Windows::ApplicationModel::Package::Current();
72 if (package) {
73 const auto path = package.InstalledLocation();
74 if (path) {
75 return std::wstring(path.Path());
76 }
77 }
78 }
79 catch (...) {
80 }
81
82 return std::wstring();
83 }
84
85 static PyStatus
set_process_name(PyConfig * config)86 set_process_name(PyConfig *config)
87 {
88 PyStatus status = PyStatus_Ok();
89 std::wstring executable;
90
91 const auto home = get_package_home();
92 const auto family = get_package_family();
93
94 if (!family.empty()) {
95 PWSTR localAppData;
96 if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0,
97 NULL, &localAppData))) {
98 executable = std::wstring(localAppData)
99 + L"\\Microsoft\\WindowsApps\\"
100 + family
101 + L"\\"
102 + PROGNAME;
103
104 CoTaskMemFree(localAppData);
105 }
106 }
107
108 /* Only use module filename if we don't have a home */
109 if (home.empty() && executable.empty()) {
110 executable.resize(MAX_PATH);
111 while (true) {
112 DWORD len = GetModuleFileNameW(
113 NULL, executable.data(), (DWORD)executable.size());
114 if (len == 0) {
115 executable.clear();
116 break;
117 } else if (len == executable.size() &&
118 GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
119 executable.resize(len * 2);
120 } else {
121 executable.resize(len);
122 break;
123 }
124 }
125 size_t i = executable.find_last_of(L"/\\");
126 if (i == std::wstring::npos) {
127 executable = PROGNAME;
128 } else {
129 executable.replace(i + 1, std::wstring::npos, PROGNAME);
130 }
131 }
132
133 if (!home.empty()) {
134 status = PyConfig_SetString(config, &config->home, home.c_str());
135 if (PyStatus_Exception(status)) {
136 return status;
137 }
138 }
139
140 const wchar_t *launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
141 if (launcherPath) {
142 if (!executable.empty()) {
143 status = PyConfig_SetString(config, &config->base_executable,
144 executable.c_str());
145 if (PyStatus_Exception(status)) {
146 return status;
147 }
148 }
149
150 status = PyConfig_SetString(
151 config, &config->executable, launcherPath);
152
153 /* bpo-35873: Clear the environment variable to avoid it being
154 * inherited by child processes. */
155 _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
156 } else if (!executable.empty()) {
157 status = PyConfig_SetString(
158 config, &config->executable, executable.c_str());
159 }
160
161 return status;
162 }
163
164 int
wmain(int argc,wchar_t ** argv)165 wmain(int argc, wchar_t **argv)
166 {
167 PyStatus status;
168 PyPreConfig preconfig;
169 PyConfig config;
170
171 const wchar_t *moduleName = NULL;
172 const wchar_t *p = wcsrchr(argv[0], L'\\');
173 if (!p) {
174 p = argv[0];
175 }
176 if (p) {
177 if (*p == L'\\') {
178 p++;
179 }
180
181 if (wcsnicmp(p, L"pip", 3) == 0) {
182 moduleName = L"pip";
183 } else if (wcsnicmp(p, L"idle", 4) == 0) {
184 moduleName = L"idlelib";
185 }
186 }
187
188 PyPreConfig_InitPythonConfig(&preconfig);
189 if (!moduleName) {
190 status = Py_PreInitializeFromArgs(&preconfig, argc, argv);
191 if (PyStatus_Exception(status)) {
192 goto fail_without_config;
193 }
194 }
195
196 PyConfig_InitPythonConfig(&config);
197
198 status = PyConfig_SetArgv(&config, argc, argv);
199 if (PyStatus_Exception(status)) {
200 goto fail;
201 }
202 if (moduleName) {
203 config.parse_argv = 0;
204 }
205
206 status = set_process_name(&config);
207 if (PyStatus_Exception(status)) {
208 goto fail;
209 }
210
211 p = _wgetenv(L"PYTHONUSERBASE");
212 if (!p || !*p) {
213 _wputenv_s(L"PYTHONUSERBASE", get_user_base().c_str());
214 }
215
216 if (moduleName) {
217 status = PyConfig_SetString(&config, &config.run_module, moduleName);
218 if (PyStatus_Exception(status)) {
219 goto fail;
220 }
221 status = PyConfig_SetString(&config, &config.run_filename, NULL);
222 if (PyStatus_Exception(status)) {
223 goto fail;
224 }
225 status = PyConfig_SetString(&config, &config.run_command, NULL);
226 if (PyStatus_Exception(status)) {
227 goto fail;
228 }
229 }
230
231 status = Py_InitializeFromConfig(&config);
232 if (PyStatus_Exception(status)) {
233 goto fail;
234 }
235 PyConfig_Clear(&config);
236
237 return Py_RunMain();
238
239 fail:
240 PyConfig_Clear(&config);
241 fail_without_config:
242 if (PyStatus_IsExit(status)) {
243 return status.exitcode;
244 }
245 assert(PyStatus_Exception(status));
246 Py_ExitStatusException(status);
247 /* Unreachable code */
248 return 0;
249 }
250
251 #ifdef PYTHONW
252
wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)253 int WINAPI wWinMain(
254 HINSTANCE hInstance, /* handle to current instance */
255 HINSTANCE hPrevInstance, /* handle to previous instance */
256 LPWSTR lpCmdLine, /* pointer to command line */
257 int nCmdShow /* show state of window */
258 )
259 {
260 return wmain(__argc, __wargv);
261 }
262
263 #endif
264