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
10 #include <winrt\Windows.ApplicationModel.h>
11 #include <winrt\Windows.Storage.h>
12
13 #ifdef PYTHONW
14 #ifdef _DEBUG
15 const wchar_t *PROGNAME = L"pythonw_d.exe";
16 #else
17 const wchar_t *PROGNAME = L"pythonw.exe";
18 #endif
19 #else
20 #ifdef _DEBUG
21 const wchar_t *PROGNAME = L"python_d.exe";
22 #else
23 const wchar_t *PROGNAME = L"python.exe";
24 #endif
25 #endif
26
27 static void
set_user_base()28 set_user_base()
29 {
30 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 }
47 }
48
49 static const wchar_t *
get_argv0(const wchar_t * argv0)50 get_argv0(const wchar_t *argv0)
51 {
52 winrt::hstring installPath;
53 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
72 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 }
83
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
127 static wchar_t *
get_process_name()128 get_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
155 int
wmain(int argc,wchar_t ** argv)156 wmain(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
wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)217 int 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
228