blob: 2352f45e8a3d2a196623519063b87b77873f70fb [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 }
125 }
126
127 if (!home.empty()) {
128 status = PyConfig_SetString(config, &config->home, home.c_str());
129 if (PyStatus_Exception(status)) {
130 return status;
131 }
132 }
133
134 const wchar_t *launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
135 if (launcherPath) {
136 if (!executable.empty()) {
137 status = PyConfig_SetString(config, &config->base_executable,
138 executable.c_str());
139 if (PyStatus_Exception(status)) {
140 return status;
141 }
142 }
143
144 status = PyConfig_SetString(
145 config, &config->executable, launcherPath);
146
147 /* bpo-35873: Clear the environment variable to avoid it being
148 * inherited by child processes. */
149 _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
150 } else if (!executable.empty()) {
151 status = PyConfig_SetString(
152 config, &config->executable, executable.c_str());
153 }
154
155 return status;
Steve Dower0cd63912018-12-10 18:52:57 -0800156}
157
158int
159wmain(int argc, wchar_t **argv)
160{
Steve Dower323e7432019-06-29 14:28:59 -0700161 PyStatus status;
Steve Dower0cd63912018-12-10 18:52:57 -0800162
Steve Dower323e7432019-06-29 14:28:59 -0700163 PyPreConfig preconfig;
164 PyConfig config;
165
166 PyPreConfig_InitPythonConfig(&preconfig);
167 status = Py_PreInitializeFromArgs(&preconfig, argc, argv);
168 if (PyStatus_Exception(status)) {
169 goto fail_without_config;
Steve Dower0cd63912018-12-10 18:52:57 -0800170 }
171
Steve Dower323e7432019-06-29 14:28:59 -0700172 status = PyConfig_InitPythonConfig(&config);
173 if (PyStatus_Exception(status)) {
174 goto fail_without_config;
Steve Dower0cd63912018-12-10 18:52:57 -0800175 }
176
Steve Dower323e7432019-06-29 14:28:59 -0700177 status = PyConfig_SetArgv(&config, argc, argv);
178 if (PyStatus_Exception(status)) {
179 goto fail;
180 }
Steve Dower0cd63912018-12-10 18:52:57 -0800181
Steve Dower323e7432019-06-29 14:28:59 -0700182 status = set_process_name(&config);
183 if (PyStatus_Exception(status)) {
184 goto fail;
185 }
186
187 const wchar_t *p = _wgetenv(L"PYTHONUSERBASE");
188 if (!p || !*p) {
189 _wputenv_s(L"PYTHONUSERBASE", get_user_base().c_str());
190 }
191
192 p = wcsrchr(argv[0], L'\\');
193 if (!p) {
194 p = argv[0];
195 }
196 if (p) {
197 if (*p == L'\\') {
198 p++;
199 }
200
201 const wchar_t *moduleName = NULL;
202 if (wcsnicmp(p, L"pip", 3) == 0) {
203 moduleName = L"pip";
204 /* No longer required when pip 19.1 is added */
205 _wputenv_s(L"PIP_USER", L"true");
206 } else if (wcsnicmp(p, L"idle", 4) == 0) {
207 moduleName = L"idlelib";
208 }
209
210 if (moduleName) {
211 status = PyConfig_SetString(&config, &config.run_module, moduleName);
212 if (PyStatus_Exception(status)) {
213 goto fail;
Steve Dower0cd63912018-12-10 18:52:57 -0800214 }
Steve Dower323e7432019-06-29 14:28:59 -0700215 status = PyConfig_SetString(&config, &config.run_filename, NULL);
216 if (PyStatus_Exception(status)) {
217 goto fail;
218 }
219 status = PyConfig_SetString(&config, &config.run_command, NULL);
220 if (PyStatus_Exception(status)) {
221 goto fail;
Steve Dower0cd63912018-12-10 18:52:57 -0800222 }
223 }
224 }
225
Steve Dower323e7432019-06-29 14:28:59 -0700226 status = Py_InitializeFromConfig(&config);
227 if (PyStatus_Exception(status)) {
228 goto fail;
229 }
230 PyConfig_Clear(&config);
Steve Dower0cd63912018-12-10 18:52:57 -0800231
Steve Dower323e7432019-06-29 14:28:59 -0700232 return Py_RunMain();
Steve Dower0cd63912018-12-10 18:52:57 -0800233
Steve Dower323e7432019-06-29 14:28:59 -0700234fail:
235 PyConfig_Clear(&config);
236fail_without_config:
237 if (PyStatus_IsExit(status)) {
238 return status.exitcode;
239 }
240 assert(PyStatus_Exception(status));
241 Py_ExitStatusException(status);
242 /* Unreachable code */
243 return 0;
Steve Dower0cd63912018-12-10 18:52:57 -0800244}
245
246#ifdef PYTHONW
247
248int WINAPI wWinMain(
249 HINSTANCE hInstance, /* handle to current instance */
250 HINSTANCE hPrevInstance, /* handle to previous instance */
251 LPWSTR lpCmdLine, /* pointer to command line */
252 int nCmdShow /* show state of window */
253)
254{
255 return wmain(__argc, __wargv);
256}
257
258#endif