You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
6.6 KiB

  1. /* Main program when embedded in a UWP application on Windows */
  2. #include "Python.h"
  3. #include <string.h>
  4. #define WIN32_LEAN_AND_MEAN
  5. #include <Windows.h>
  6. #include <shellapi.h>
  7. #include <shlobj.h>
  8. #include <string>
  9. #include <winrt\Windows.ApplicationModel.h>
  10. #include <winrt\Windows.Storage.h>
  11. #ifdef PYTHONW
  12. #ifdef _DEBUG
  13. const wchar_t *PROGNAME = L"pythonw_d.exe";
  14. #else
  15. const wchar_t *PROGNAME = L"pythonw.exe";
  16. #endif
  17. #else
  18. #ifdef _DEBUG
  19. const wchar_t *PROGNAME = L"python_d.exe";
  20. #else
  21. const wchar_t *PROGNAME = L"python.exe";
  22. #endif
  23. #endif
  24. static std::wstring
  25. get_user_base()
  26. {
  27. try {
  28. const auto appData = winrt::Windows::Storage::ApplicationData::Current();
  29. if (appData) {
  30. const auto localCache = appData.LocalCacheFolder();
  31. if (localCache) {
  32. auto path = localCache.Path();
  33. if (!path.empty()) {
  34. return std::wstring(path) + L"\\local-packages";
  35. }
  36. }
  37. }
  38. } catch (...) {
  39. }
  40. return std::wstring();
  41. }
  42. static std::wstring
  43. get_package_family()
  44. {
  45. try {
  46. const auto package = winrt::Windows::ApplicationModel::Package::Current();
  47. if (package) {
  48. const auto id = package.Id();
  49. if (id) {
  50. return std::wstring(id.FamilyName());
  51. }
  52. }
  53. }
  54. catch (...) {
  55. }
  56. return std::wstring();
  57. }
  58. static std::wstring
  59. get_package_home()
  60. {
  61. try {
  62. const auto package = winrt::Windows::ApplicationModel::Package::Current();
  63. if (package) {
  64. const auto path = package.InstalledLocation();
  65. if (path) {
  66. return std::wstring(path.Path());
  67. }
  68. }
  69. }
  70. catch (...) {
  71. }
  72. return std::wstring();
  73. }
  74. static PyStatus
  75. set_process_name(PyConfig *config)
  76. {
  77. PyStatus status = PyStatus_Ok();
  78. std::wstring executable;
  79. const auto home = get_package_home();
  80. const auto family = get_package_family();
  81. if (!family.empty()) {
  82. PWSTR localAppData;
  83. if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0,
  84. NULL, &localAppData))) {
  85. executable = std::wstring(localAppData)
  86. + L"\\Microsoft\\WindowsApps\\"
  87. + family
  88. + L"\\"
  89. + PROGNAME;
  90. CoTaskMemFree(localAppData);
  91. }
  92. }
  93. /* Only use module filename if we don't have a home */
  94. if (home.empty() && executable.empty()) {
  95. executable.resize(MAX_PATH);
  96. while (true) {
  97. DWORD len = GetModuleFileNameW(
  98. NULL, executable.data(), (DWORD)executable.size());
  99. if (len == 0) {
  100. executable.clear();
  101. break;
  102. } else if (len == executable.size() &&
  103. GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  104. executable.resize(len * 2);
  105. } else {
  106. executable.resize(len);
  107. break;
  108. }
  109. }
  110. size_t i = executable.find_last_of(L"/\\");
  111. if (i == std::wstring::npos) {
  112. executable = PROGNAME;
  113. } else {
  114. executable.replace(i + 1, std::wstring::npos, PROGNAME);
  115. }
  116. }
  117. if (!home.empty()) {
  118. status = PyConfig_SetString(config, &config->home, home.c_str());
  119. if (PyStatus_Exception(status)) {
  120. return status;
  121. }
  122. }
  123. const wchar_t *launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
  124. if (launcherPath) {
  125. if (!executable.empty()) {
  126. status = PyConfig_SetString(config, &config->base_executable,
  127. executable.c_str());
  128. if (PyStatus_Exception(status)) {
  129. return status;
  130. }
  131. }
  132. status = PyConfig_SetString(
  133. config, &config->executable, launcherPath);
  134. /* bpo-35873: Clear the environment variable to avoid it being
  135. * inherited by child processes. */
  136. _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
  137. } else if (!executable.empty()) {
  138. status = PyConfig_SetString(
  139. config, &config->executable, executable.c_str());
  140. }
  141. return status;
  142. }
  143. int
  144. wmain(int argc, wchar_t **argv)
  145. {
  146. PyStatus status;
  147. PyPreConfig preconfig;
  148. PyConfig config;
  149. const wchar_t *moduleName = NULL;
  150. const wchar_t *p = wcsrchr(argv[0], L'\\');
  151. if (!p) {
  152. p = argv[0];
  153. }
  154. if (p) {
  155. if (*p == L'\\') {
  156. p++;
  157. }
  158. if (wcsnicmp(p, L"pip", 3) == 0) {
  159. moduleName = L"pip";
  160. } else if (wcsnicmp(p, L"idle", 4) == 0) {
  161. moduleName = L"idlelib";
  162. }
  163. }
  164. PyPreConfig_InitPythonConfig(&preconfig);
  165. if (!moduleName) {
  166. status = Py_PreInitializeFromArgs(&preconfig, argc, argv);
  167. if (PyStatus_Exception(status)) {
  168. goto fail_without_config;
  169. }
  170. }
  171. status = PyConfig_InitPythonConfig(&config);
  172. if (PyStatus_Exception(status)) {
  173. goto fail_without_config;
  174. }
  175. status = PyConfig_SetArgv(&config, argc, argv);
  176. if (PyStatus_Exception(status)) {
  177. goto fail;
  178. }
  179. if (moduleName) {
  180. config.parse_argv = 0;
  181. }
  182. status = set_process_name(&config);
  183. if (PyStatus_Exception(status)) {
  184. goto fail;
  185. }
  186. p = _wgetenv(L"PYTHONUSERBASE");
  187. if (!p || !*p) {
  188. _wputenv_s(L"PYTHONUSERBASE", get_user_base().c_str());
  189. }
  190. if (moduleName) {
  191. status = PyConfig_SetString(&config, &config.run_module, moduleName);
  192. if (PyStatus_Exception(status)) {
  193. goto fail;
  194. }
  195. status = PyConfig_SetString(&config, &config.run_filename, NULL);
  196. if (PyStatus_Exception(status)) {
  197. goto fail;
  198. }
  199. status = PyConfig_SetString(&config, &config.run_command, NULL);
  200. if (PyStatus_Exception(status)) {
  201. goto fail;
  202. }
  203. }
  204. status = Py_InitializeFromConfig(&config);
  205. if (PyStatus_Exception(status)) {
  206. goto fail;
  207. }
  208. PyConfig_Clear(&config);
  209. return Py_RunMain();
  210. fail:
  211. PyConfig_Clear(&config);
  212. fail_without_config:
  213. if (PyStatus_IsExit(status)) {
  214. return status.exitcode;
  215. }
  216. assert(PyStatus_Exception(status));
  217. Py_ExitStatusException(status);
  218. /* Unreachable code */
  219. return 0;
  220. }
  221. #ifdef PYTHONW
  222. int WINAPI wWinMain(
  223. HINSTANCE hInstance, /* handle to current instance */
  224. HINSTANCE hPrevInstance, /* handle to previous instance */
  225. LPWSTR lpCmdLine, /* pointer to command line */
  226. int nCmdShow /* show state of window */
  227. )
  228. {
  229. return wmain(__argc, __wargv);
  230. }
  231. #endif