mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			287 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* 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>
 | |
| 
 | |
| #include <appmodel.h>
 | |
| #include <winrt\Windows.ApplicationModel.h>
 | |
| #include <winrt\Windows.Storage.h>
 | |
| 
 | |
| #ifdef PYTHONW
 | |
| #ifdef _DEBUG
 | |
| const wchar_t *PROGNAME = L"pythonw_d.exe";
 | |
| #else
 | |
| const wchar_t *PROGNAME = L"pythonw.exe";
 | |
| #endif
 | |
| #else
 | |
| #ifdef _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
 | 
