228 lines
5.5 KiB
C++
228 lines
5.5 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 <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 void
|
||
|
set_user_base()
|
||
|
{
|
||
|
wchar_t envBuffer[2048];
|
||
|
try {
|
||
|
const auto appData = winrt::Windows::Storage::ApplicationData::Current();
|
||
|
if (appData) {
|
||
|
const auto localCache = appData.LocalCacheFolder();
|
||
|
if (localCache) {
|
||
|
auto path = localCache.Path();
|
||
|
if (!path.empty() &&
|
||
|
!wcscpy_s(envBuffer, path.c_str()) &&
|
||
|
!wcscat_s(envBuffer, L"\\local-packages")
|
||
|
) {
|
||
|
_wputenv_s(L"PYTHONUSERBASE", envBuffer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} catch (...) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const wchar_t *
|
||
|
get_argv0(const wchar_t *argv0)
|
||
|
{
|
||
|
winrt::hstring installPath;
|
||
|
const wchar_t *launcherPath;
|
||
|
wchar_t *buffer;
|
||
|
size_t len;
|
||
|
|
||
|
launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
|
||
|
if (launcherPath && launcherPath[0]) {
|
||
|
len = wcslen(launcherPath) + 1;
|
||
|
buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
|
||
|
if (!buffer) {
|
||
|
Py_FatalError("out of memory");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (wcscpy_s(buffer, len, launcherPath)) {
|
||
|
Py_FatalError("failed to copy to buffer");
|
||
|
return NULL;
|
||
|
}
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
const auto package = winrt::Windows::ApplicationModel::Package::Current();
|
||
|
if (package) {
|
||
|
const auto install = package.InstalledLocation();
|
||
|
if (install) {
|
||
|
installPath = install.Path();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
catch (...) {
|
||
|
}
|
||
|
|
||
|
if (!installPath.empty()) {
|
||
|
len = installPath.size() + wcslen(PROGNAME) + 2;
|
||
|
} else {
|
||
|
len = wcslen(argv0) + wcslen(PROGNAME) + 1;
|
||
|
}
|
||
|
|
||
|
buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
|
||
|
if (!buffer) {
|
||
|
Py_FatalError("out of memory");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!installPath.empty()) {
|
||
|
if (wcscpy_s(buffer, len, installPath.c_str())) {
|
||
|
Py_FatalError("failed to copy to buffer");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (wcscat_s(buffer, len, L"\\")) {
|
||
|
Py_FatalError("failed to concatenate backslash");
|
||
|
return NULL;
|
||
|
}
|
||
|
} else {
|
||
|
if (wcscpy_s(buffer, len, argv0)) {
|
||
|
Py_FatalError("failed to copy argv[0]");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
wchar_t *name = wcsrchr(buffer, L'\\');
|
||
|
if (name) {
|
||
|
name[1] = L'\0';
|
||
|
} else {
|
||
|
buffer[0] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (wcscat_s(buffer, len, PROGNAME)) {
|
||
|
Py_FatalError("failed to concatenate program name");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
static wchar_t *
|
||
|
get_process_name()
|
||
|
{
|
||
|
DWORD bufferLen = MAX_PATH;
|
||
|
DWORD len = bufferLen;
|
||
|
wchar_t *r = NULL;
|
||
|
|
||
|
while (!r) {
|
||
|
r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
|
||
|
if (!r) {
|
||
|
Py_FatalError("out of memory");
|
||
|
return NULL;
|
||
|
}
|
||
|
len = GetModuleFileNameW(NULL, r, bufferLen);
|
||
|
if (len == 0) {
|
||
|
free((void *)r);
|
||
|
return NULL;
|
||
|
} else if (len == bufferLen &&
|
||
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
free(r);
|
||
|
r = NULL;
|
||
|
bufferLen *= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
wmain(int argc, wchar_t **argv)
|
||
|
{
|
||
|
const wchar_t **new_argv;
|
||
|
int new_argc;
|
||
|
const wchar_t *exeName;
|
||
|
|
||
|
new_argc = argc;
|
||
|
new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
|
||
|
if (new_argv == NULL) {
|
||
|
Py_FatalError("out of memory");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
exeName = get_process_name();
|
||
|
|
||
|
new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
|
||
|
for (int i = 1; i < argc; ++i) {
|
||
|
new_argv[i] = argv[i];
|
||
|
}
|
||
|
|
||
|
set_user_base();
|
||
|
|
||
|
if (exeName) {
|
||
|
const wchar_t *p = wcsrchr(exeName, L'\\');
|
||
|
if (p) {
|
||
|
const wchar_t *moduleName = NULL;
|
||
|
if (*p++ == L'\\') {
|
||
|
if (wcsnicmp(p, L"pip", 3) == 0) {
|
||
|
moduleName = L"pip";
|
||
|
_wputenv_s(L"PIP_USER", L"true");
|
||
|
}
|
||
|
else if (wcsnicmp(p, L"idle", 4) == 0) {
|
||
|
moduleName = L"idlelib";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (moduleName) {
|
||
|
new_argc += 2;
|
||
|
for (int i = argc; i >= 1; --i) {
|
||
|
new_argv[i + 2] = new_argv[i];
|
||
|
}
|
||
|
new_argv[1] = L"-m";
|
||
|
new_argv[2] = moduleName;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Override program_full_path from here so that
|
||
|
sys.executable is set correctly. */
|
||
|
_Py_SetProgramFullPath(new_argv[0]);
|
||
|
|
||
|
int result = Py_Main(new_argc, (wchar_t **)new_argv);
|
||
|
|
||
|
free((void *)exeName);
|
||
|
free((void *)new_argv);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#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
|