mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +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
 |