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.

227 lines
5.5 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 <winrt\Windows.ApplicationModel.h>
  8. #include <winrt\Windows.Storage.h>
  9. #ifdef PYTHONW
  10. #ifdef _DEBUG
  11. const wchar_t *PROGNAME = L"pythonw_d.exe";
  12. #else
  13. const wchar_t *PROGNAME = L"pythonw.exe";
  14. #endif
  15. #else
  16. #ifdef _DEBUG
  17. const wchar_t *PROGNAME = L"python_d.exe";
  18. #else
  19. const wchar_t *PROGNAME = L"python.exe";
  20. #endif
  21. #endif
  22. static void
  23. set_user_base()
  24. {
  25. wchar_t envBuffer[2048];
  26. try {
  27. const auto appData = winrt::Windows::Storage::ApplicationData::Current();
  28. if (appData) {
  29. const auto localCache = appData.LocalCacheFolder();
  30. if (localCache) {
  31. auto path = localCache.Path();
  32. if (!path.empty() &&
  33. !wcscpy_s(envBuffer, path.c_str()) &&
  34. !wcscat_s(envBuffer, L"\\local-packages")
  35. ) {
  36. _wputenv_s(L"PYTHONUSERBASE", envBuffer);
  37. }
  38. }
  39. }
  40. } catch (...) {
  41. }
  42. }
  43. static const wchar_t *
  44. get_argv0(const wchar_t *argv0)
  45. {
  46. winrt::hstring installPath;
  47. const wchar_t *launcherPath;
  48. wchar_t *buffer;
  49. size_t len;
  50. launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
  51. if (launcherPath && launcherPath[0]) {
  52. len = wcslen(launcherPath) + 1;
  53. buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
  54. if (!buffer) {
  55. Py_FatalError("out of memory");
  56. return NULL;
  57. }
  58. if (wcscpy_s(buffer, len, launcherPath)) {
  59. Py_FatalError("failed to copy to buffer");
  60. return NULL;
  61. }
  62. return buffer;
  63. }
  64. try {
  65. const auto package = winrt::Windows::ApplicationModel::Package::Current();
  66. if (package) {
  67. const auto install = package.InstalledLocation();
  68. if (install) {
  69. installPath = install.Path();
  70. }
  71. }
  72. }
  73. catch (...) {
  74. }
  75. if (!installPath.empty()) {
  76. len = installPath.size() + wcslen(PROGNAME) + 2;
  77. } else {
  78. len = wcslen(argv0) + wcslen(PROGNAME) + 1;
  79. }
  80. buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
  81. if (!buffer) {
  82. Py_FatalError("out of memory");
  83. return NULL;
  84. }
  85. if (!installPath.empty()) {
  86. if (wcscpy_s(buffer, len, installPath.c_str())) {
  87. Py_FatalError("failed to copy to buffer");
  88. return NULL;
  89. }
  90. if (wcscat_s(buffer, len, L"\\")) {
  91. Py_FatalError("failed to concatenate backslash");
  92. return NULL;
  93. }
  94. } else {
  95. if (wcscpy_s(buffer, len, argv0)) {
  96. Py_FatalError("failed to copy argv[0]");
  97. return NULL;
  98. }
  99. wchar_t *name = wcsrchr(buffer, L'\\');
  100. if (name) {
  101. name[1] = L'\0';
  102. } else {
  103. buffer[0] = L'\0';
  104. }
  105. }
  106. if (wcscat_s(buffer, len, PROGNAME)) {
  107. Py_FatalError("failed to concatenate program name");
  108. return NULL;
  109. }
  110. return buffer;
  111. }
  112. static wchar_t *
  113. get_process_name()
  114. {
  115. DWORD bufferLen = MAX_PATH;
  116. DWORD len = bufferLen;
  117. wchar_t *r = NULL;
  118. while (!r) {
  119. r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
  120. if (!r) {
  121. Py_FatalError("out of memory");
  122. return NULL;
  123. }
  124. len = GetModuleFileNameW(NULL, r, bufferLen);
  125. if (len == 0) {
  126. free((void *)r);
  127. return NULL;
  128. } else if (len == bufferLen &&
  129. GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  130. free(r);
  131. r = NULL;
  132. bufferLen *= 2;
  133. }
  134. }
  135. return r;
  136. }
  137. int
  138. wmain(int argc, wchar_t **argv)
  139. {
  140. const wchar_t **new_argv;
  141. int new_argc;
  142. const wchar_t *exeName;
  143. new_argc = argc;
  144. new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
  145. if (new_argv == NULL) {
  146. Py_FatalError("out of memory");
  147. return -1;
  148. }
  149. exeName = get_process_name();
  150. new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
  151. for (int i = 1; i < argc; ++i) {
  152. new_argv[i] = argv[i];
  153. }
  154. set_user_base();
  155. if (exeName) {
  156. const wchar_t *p = wcsrchr(exeName, L'\\');
  157. if (p) {
  158. const wchar_t *moduleName = NULL;
  159. if (*p++ == L'\\') {
  160. if (wcsnicmp(p, L"pip", 3) == 0) {
  161. moduleName = L"pip";
  162. _wputenv_s(L"PIP_USER", L"true");
  163. }
  164. else if (wcsnicmp(p, L"idle", 4) == 0) {
  165. moduleName = L"idlelib";
  166. }
  167. }
  168. if (moduleName) {
  169. new_argc += 2;
  170. for (int i = argc; i >= 1; --i) {
  171. new_argv[i + 2] = new_argv[i];
  172. }
  173. new_argv[1] = L"-m";
  174. new_argv[2] = moduleName;
  175. }
  176. }
  177. }
  178. /* Override program_full_path from here so that
  179. sys.executable is set correctly. */
  180. _Py_SetProgramFullPath(new_argv[0]);
  181. int result = Py_Main(new_argc, (wchar_t **)new_argv);
  182. free((void *)exeName);
  183. free((void *)new_argv);
  184. return result;
  185. }
  186. #ifdef PYTHONW
  187. int WINAPI wWinMain(
  188. HINSTANCE hInstance, /* handle to current instance */
  189. HINSTANCE hPrevInstance, /* handle to previous instance */
  190. LPWSTR lpCmdLine, /* pointer to command line */
  191. int nCmdShow /* show state of window */
  192. )
  193. {
  194. return wmain(__argc, __wargv);
  195. }
  196. #endif