blob: 88369e8fbfeb38da48c975b7d1a60ebad41a8d4f [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>
Steve Dower323e7432019-06-29 14:28:59 -07009#include <shlobj.h>
10
11#include <string>
Steve Dower0cd63912018-12-10 18:52:57 -080012
Steve Dower0cd63912018-12-10 18:52:57 -080013#include <winrt\Windows.ApplicationModel.h>
14#include <winrt\Windows.Storage.h>
Steve Dower0cd63912018-12-10 18:52:57 -080015
16#ifdef PYTHONW
17#ifdef _DEBUG
18const wchar_t *PROGNAME = L"pythonw_d.exe";
19#else
20const wchar_t *PROGNAME = L"pythonw.exe";
21#endif
22#else
23#ifdef _DEBUG
24const wchar_t *PROGNAME = L"python_d.exe";
25#else
26const wchar_t *PROGNAME = L"python.exe";
27#endif
28#endif
29
Steve Dower323e7432019-06-29 14:28:59 -070030static std::wstring
31get_user_base()
Steve Dower0cd63912018-12-10 18:52:57 -080032{
Steve Dower0cd63912018-12-10 18:52:57 -080033 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();
Steve Dower323e7432019-06-29 14:28:59 -070039 if (!path.empty()) {
40 return std::wstring(path) + L"\\local-packages";
Steve Dower0cd63912018-12-10 18:52:57 -080041 }
42 }
43 }
44 } catch (...) {
45 }
Steve Dower323e7432019-06-29 14:28:59 -070046 return std::wstring();
Steve Dower0cd63912018-12-10 18:52:57 -080047}
48
Steve Dower323e7432019-06-29 14:28:59 -070049static std::wstring
50get_package_family()
Steve Dower0cd63912018-12-10 18:52:57 -080051{
Steve Dower0cd63912018-12-10 18:52:57 -080052 try {
53 const auto package = winrt::Windows::ApplicationModel::Package::Current();
54 if (package) {
Steve Dower323e7432019-06-29 14:28:59 -070055 const auto id = package.Id();
56 if (id) {
57 return std::wstring(id.FamilyName());
Steve Dower0cd63912018-12-10 18:52:57 -080058 }
59 }
60 }
61 catch (...) {
62 }
Steve Dower0cd63912018-12-10 18:52:57 -080063
Steve Dower323e7432019-06-29 14:28:59 -070064 return std::wstring();
Steve Dower0cd63912018-12-10 18:52:57 -080065}
66
Steve Dower323e7432019-06-29 14:28:59 -070067static std::wstring
68get_package_home()
Steve Dower0cd63912018-12-10 18:52:57 -080069{
Steve Dower323e7432019-06-29 14:28:59 -070070 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 }
Steve Dower0cd63912018-12-10 18:52:57 -080077 }
Steve Dower323e7432019-06-29 14:28:59 -070078 }
79 catch (...) {
80 }
81
82 return std::wstring();
83}
84
85static PyStatus
86set_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);
Steve Dower0cd63912018-12-10 18:52:57 -0800105 }
106 }
107
Steve Dower323e7432019-06-29 14:28:59 -0700108 /* 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 }
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700125 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 }
Steve Dower323e7432019-06-29 14:28:59 -0700131 }
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;
Steve Dower0cd63912018-12-10 18:52:57 -0800162}
163
164int
165wmain(int argc, wchar_t **argv)
166{
Steve Dower323e7432019-06-29 14:28:59 -0700167 PyStatus status;
Steve Dower323e7432019-06-29 14:28:59 -0700168 PyPreConfig preconfig;
169 PyConfig config;
170
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700171 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
Victor Stinnerbdace212019-10-01 00:46:42 +0200188 PyPreConfig_InitPythonConfig(&preconfig);
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700189 if (!moduleName) {
190 status = Py_PreInitializeFromArgs(&preconfig, argc, argv);
191 if (PyStatus_Exception(status)) {
192 goto fail_without_config;
193 }
Steve Dower0cd63912018-12-10 18:52:57 -0800194 }
195
Miss Islington (bot)d49f0962019-10-01 03:26:04 -0700196 PyConfig_InitPythonConfig(&config);
Steve Dower0cd63912018-12-10 18:52:57 -0800197
Steve Dower323e7432019-06-29 14:28:59 -0700198 status = PyConfig_SetArgv(&config, argc, argv);
199 if (PyStatus_Exception(status)) {
200 goto fail;
201 }
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700202 if (moduleName) {
203 config.parse_argv = 0;
204 }
Steve Dower0cd63912018-12-10 18:52:57 -0800205
Steve Dower323e7432019-06-29 14:28:59 -0700206 status = set_process_name(&config);
207 if (PyStatus_Exception(status)) {
208 goto fail;
209 }
210
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700211 p = _wgetenv(L"PYTHONUSERBASE");
Steve Dower323e7432019-06-29 14:28:59 -0700212 if (!p || !*p) {
213 _wputenv_s(L"PYTHONUSERBASE", get_user_base().c_str());
214 }
215
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700216 if (moduleName) {
217 status = PyConfig_SetString(&config, &config.run_module, moduleName);
218 if (PyStatus_Exception(status)) {
219 goto fail;
Steve Dower323e7432019-06-29 14:28:59 -0700220 }
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700221 status = PyConfig_SetString(&config, &config.run_filename, NULL);
222 if (PyStatus_Exception(status)) {
223 goto fail;
Steve Dower323e7432019-06-29 14:28:59 -0700224 }
Miss Islington (bot)4b7ce102019-07-24 15:31:48 -0700225 status = PyConfig_SetString(&config, &config.run_command, NULL);
226 if (PyStatus_Exception(status)) {
227 goto fail;
Steve Dower0cd63912018-12-10 18:52:57 -0800228 }
229 }
230
Steve Dower323e7432019-06-29 14:28:59 -0700231 status = Py_InitializeFromConfig(&config);
232 if (PyStatus_Exception(status)) {
233 goto fail;
234 }
235 PyConfig_Clear(&config);
Steve Dower0cd63912018-12-10 18:52:57 -0800236
Steve Dower323e7432019-06-29 14:28:59 -0700237 return Py_RunMain();
Steve Dower0cd63912018-12-10 18:52:57 -0800238
Steve Dower323e7432019-06-29 14:28:59 -0700239fail:
240 PyConfig_Clear(&config);
241fail_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;
Steve Dower0cd63912018-12-10 18:52:57 -0800249}
250
251#ifdef PYTHONW
252
253int 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