• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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