| /* Main program when embedded in a UWP application on Windows */ | |
| #include "Python.h" | |
| #include <string.h> | |
| #define WIN32_LEAN_AND_MEAN | |
| #include <Windows.h> | |
| #include <shellapi.h> | |
| #include <shlobj.h> | |
| #include <string> | |
| #if defined(__clang__) | |
| #define _SILENCE_CLANG_COROUTINE_MESSAGE | |
| #endif | |
| #define _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS | |
| #include <appmodel.h> | |
| #include <winrt\Windows.ApplicationModel.h> | |
| #include <winrt\Windows.Storage.h> | |
| #ifdef PYTHONW | |
| #ifdef Py_DEBUG | |
| const wchar_t *PROGNAME = L"pythonw_d.exe"; | |
| #else | |
| const wchar_t *PROGNAME = L"pythonw.exe"; | |
| #endif | |
| #else | |
| #ifdef Py_DEBUG | |
| const wchar_t *PROGNAME = L"python_d.exe"; | |
| #else | |
| const wchar_t *PROGNAME = L"python.exe"; | |
| #endif | |
| #endif | |
| static std::wstring | |
| get_package_family() | |
| { | |
| try { | |
| UINT32 nameLength = MAX_PATH; | |
| std::wstring name; | |
| name.resize(nameLength); | |
| DWORD rc = GetCurrentPackageFamilyName(&nameLength, name.data()); | |
| if (rc == ERROR_SUCCESS) { | |
| name.resize(nameLength - 1); | |
| return name; | |
| } | |
| else if (rc != ERROR_INSUFFICIENT_BUFFER) { | |
| throw rc; | |
| } | |
| name.resize(nameLength); | |
| rc = GetCurrentPackageFamilyName(&nameLength, name.data()); | |
| if (rc != ERROR_SUCCESS) { | |
| throw rc; | |
| } | |
| name.resize(nameLength - 1); | |
| return name; | |
| } | |
| catch (...) { | |
| } | |
| return std::wstring(); | |
| } | |
| static std::wstring | |
| get_user_base() | |
| { | |
| try { | |
| const auto appData = winrt::Windows::Storage::ApplicationData::Current(); | |
| if (appData) { | |
| const auto localCache = appData.LocalCacheFolder(); | |
| if (localCache) { | |
| std::wstring path { localCache.Path().c_str() }; | |
| if (!path.empty()) { | |
| return path + L"\\local-packages"; | |
| } | |
| } | |
| } | |
| } catch (...) { | |
| } | |
| return std::wstring(); | |
| } | |
| static std::wstring | |
| get_package_home() | |
| { | |
| try { | |
| UINT32 pathLength = MAX_PATH; | |
| std::wstring path; | |
| path.resize(pathLength); | |
| DWORD rc = GetCurrentPackagePath(&pathLength, path.data()); | |
| if (rc == ERROR_SUCCESS) { | |
| path.resize(pathLength - 1); | |
| return path; | |
| } | |
| else if (rc != ERROR_INSUFFICIENT_BUFFER) { | |
| throw rc; | |
| } | |
| path.resize(pathLength); | |
| rc = GetCurrentPackagePath(&pathLength, path.data()); | |
| if (rc != ERROR_SUCCESS) { | |
| throw rc; | |
| } | |
| path.resize(pathLength - 1); | |
| return path; | |
| } | |
| catch (...) { | |
| } | |
| return std::wstring(); | |
| } | |
| static PyStatus | |
| set_process_name(PyConfig *config) | |
| { | |
| PyStatus status = PyStatus_Ok(); | |
| std::wstring executable; | |
| const auto home = get_package_home(); | |
| const auto family = get_package_family(); | |
| if (!family.empty()) { | |
| PWSTR localAppData; | |
| if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, | |
| NULL, &localAppData))) { | |
| executable = std::wstring(localAppData) | |
| + L"\\Microsoft\\WindowsApps\\" | |
| + family | |
| + L"\\" | |
| + PROGNAME; | |
| CoTaskMemFree(localAppData); | |
| } | |
| } | |
| /* Only use module filename if we don't have a home */ | |
| if (home.empty() && executable.empty()) { | |
| executable.resize(MAX_PATH); | |
| while (true) { | |
| DWORD len = GetModuleFileNameW( | |
| NULL, executable.data(), (DWORD)executable.size()); | |
| if (len == 0) { | |
| executable.clear(); | |
| break; | |
| } else if (len == executable.size() && | |
| GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | |
| executable.resize(len * 2); | |
| } else { | |
| executable.resize(len); | |
| break; | |
| } | |
| } | |
| size_t i = executable.find_last_of(L"/\\"); | |
| if (i == std::wstring::npos) { | |
| executable = PROGNAME; | |
| } else { | |
| executable.replace(i + 1, std::wstring::npos, PROGNAME); | |
| } | |
| } | |
| if (!home.empty()) { | |
| status = PyConfig_SetString(config, &config->home, home.c_str()); | |
| if (PyStatus_Exception(status)) { | |
| return status; | |
| } | |
| } | |
| const wchar_t *launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__"); | |
| if (launcherPath) { | |
| if (!executable.empty()) { | |
| status = PyConfig_SetString(config, &config->base_executable, | |
| executable.c_str()); | |
| if (PyStatus_Exception(status)) { | |
| return status; | |
| } | |
| } | |
| status = PyConfig_SetString( | |
| config, &config->executable, launcherPath); | |
| /* bpo-35873: Clear the environment variable to avoid it being | |
| * inherited by child processes. */ | |
| _wputenv_s(L"__PYVENV_LAUNCHER__", L""); | |
| } else if (!executable.empty()) { | |
| status = PyConfig_SetString( | |
| config, &config->executable, executable.c_str()); | |
| } | |
| return status; | |
| } | |
| int | |
| wmain(int argc, wchar_t **argv) | |
| { | |
| PyStatus status; | |
| PyPreConfig preconfig; | |
| PyConfig config; | |
| const wchar_t *moduleName = NULL; | |
| const wchar_t *p = wcsrchr(argv[0], L'\\'); | |
| if (!p) { | |
| p = argv[0]; | |
| } | |
| if (p) { | |
| if (*p == L'\\') { | |
| p++; | |
| } | |
| if (wcsnicmp(p, L"pip", 3) == 0) { | |
| moduleName = L"pip"; | |
| } else if (wcsnicmp(p, L"idle", 4) == 0) { | |
| moduleName = L"idlelib"; | |
| } | |
| } | |
| PyPreConfig_InitPythonConfig(&preconfig); | |
| if (!moduleName) { | |
| status = Py_PreInitializeFromArgs(&preconfig, argc, argv); | |
| if (PyStatus_Exception(status)) { | |
| goto fail_without_config; | |
| } | |
| } | |
| PyConfig_InitPythonConfig(&config); | |
| status = PyConfig_SetArgv(&config, argc, argv); | |
| if (PyStatus_Exception(status)) { | |
| goto fail; | |
| } | |
| if (moduleName) { | |
| config.parse_argv = 0; | |
| } | |
| status = set_process_name(&config); | |
| if (PyStatus_Exception(status)) { | |
| goto fail; | |
| } | |
| p = _wgetenv(L"PYTHONUSERBASE"); | |
| if (!p || !*p) { | |
| _wputenv_s(L"PYTHONUSERBASE", get_user_base().c_str()); | |
| } | |
| if (moduleName) { | |
| status = PyConfig_SetString(&config, &config.run_module, moduleName); | |
| if (PyStatus_Exception(status)) { | |
| goto fail; | |
| } | |
| status = PyConfig_SetString(&config, &config.run_filename, NULL); | |
| if (PyStatus_Exception(status)) { | |
| goto fail; | |
| } | |
| status = PyConfig_SetString(&config, &config.run_command, NULL); | |
| if (PyStatus_Exception(status)) { | |
| goto fail; | |
| } | |
| } | |
| status = Py_InitializeFromConfig(&config); | |
| if (PyStatus_Exception(status)) { | |
| goto fail; | |
| } | |
| PyConfig_Clear(&config); | |
| return Py_RunMain(); | |
| fail: | |
| PyConfig_Clear(&config); | |
| fail_without_config: | |
| if (PyStatus_IsExit(status)) { | |
| return status.exitcode; | |
| } | |
| assert(PyStatus_Exception(status)); | |
| Py_ExitStatusException(status); | |
| /* Unreachable code */ | |
| return 0; | |
| } | |
| #ifdef PYTHONW | |
| int WINAPI wWinMain( | |
| HINSTANCE hInstance, /* handle to current instance */ | |
| HINSTANCE hPrevInstance, /* handle to previous instance */ | |
| LPWSTR lpCmdLine, /* pointer to command line */ | |
| int nCmdShow /* show state of window */ | |
| ) | |
| { | |
| return wmain(__argc, __wargv); | |
| } | |
| #endif |