mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-30 08:44:57 +00:00
feat: Add Typthon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
291
typthon/PC/python_uwp.cpp
Normal file
291
typthon/PC/python_uwp.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
/* 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
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user