22#include < string.h>
33
44#include < Windows.h>
5+ #include < shlwapi.h>
56#include < stdio.h>
67
78#include < shellapi.h>
2324#define PY_WINDOWED 0
2425#endif
2526
27+ // Uncomment to add the --__fix-cwd private argument, which will reset the
28+ // working directory to the script location or user documents/profile before
29+ // running Python.
30+ // #define ENABLE_FIX_CWD
31+
2632struct {
2733 PyObject *mod;
2834 PyObject *no_install_found_error;
@@ -483,6 +489,38 @@ locate_runtime(
483489}
484490
485491
492+ #ifdef ENABLE_FIX_CWD
493+ static int
494+ fix_working_directory (const std::wstring &script)
495+ {
496+ HRESULT hr;
497+ // If we have a script, use its parent directory
498+ if (!script.empty ()) {
499+ auto end = script.find_last_of (L" /\\ " );
500+ if (end != script.npos ) {
501+ std::wstring current_dir (script.data (), end);
502+ SetCurrentDirectoryW (current_dir.c_str ());
503+ return 0 ;
504+ }
505+ }
506+ // If we have no script, assume the user's documents folder
507+ wchar_t *path;
508+ if (SUCCEEDED (hr = SHGetKnownFolderPath (FOLDERID_Documents, 0 , NULL , &path))) {
509+ SetCurrentDirectoryW (path);
510+ CoTaskMemFree (path);
511+ return 0 ;
512+ }
513+ // As a fallback, use the user's profile (e.g. for SYSTEM)
514+ if (SUCCEEDED (hr = SHGetKnownFolderPath (FOLDERID_Profile, 0 , NULL , &path))) {
515+ SetCurrentDirectoryW (path);
516+ CoTaskMemFree (path);
517+ return 0 ;
518+ }
519+ return hr;
520+ }
521+ #endif
522+
523+
486524int
487525wmain (int argc, wchar_t **argv)
488526{
@@ -504,6 +542,9 @@ wmain(int argc, wchar_t **argv)
504542
505543 const wchar_t *default_cmd;
506544 bool use_commands, use_cli_tag, use_shebangs, use_autoinstall;
545+ #ifdef ENABLE_FIX_CWD
546+ bool fix_cwd = false ;
547+ #endif
507548 per_exe_settings (argc, argv, &default_cmd, &use_commands, &use_cli_tag, &use_shebangs, &use_autoinstall);
508549
509550 if (use_commands) {
@@ -519,6 +560,12 @@ wmain(int argc, wchar_t **argv)
519560 // We handle 'exec' in native code, so it won't be in the above list
520561 if (!wcscmp (argv[1 ], L" exec" )) {
521562 skip_argc += 1 ;
563+ #ifdef ENABLE_FIX_CWD
564+ if (!wcscmp (argv[2 ], L" --__fix-cwd" )) {
565+ fix_cwd = true ;
566+ skip_argc += 1 ;
567+ }
568+ #endif
522569 use_cli_tag = argc >= 3 ;
523570 use_shebangs = argc >= 3 ;
524571 default_cmd = NULL ;
@@ -570,6 +617,15 @@ wmain(int argc, wchar_t **argv)
570617 // Theoretically shouldn't matter, but might help reduce memory usage.
571618 close_python ();
572619
620+ #ifdef ENABLE_FIX_CWD
621+ if (fix_cwd) {
622+ err = fix_working_directory (script);
623+ if (err) {
624+ fprintf (stderr, " [WARN] Failed to fix working directory (0x%08X).\n " , err);
625+ }
626+ }
627+ #endif
628+
573629 err = launch (executable.c_str (), args.c_str (), skip_argc, &exitCode);
574630
575631 // TODO: Consider sharing print_error() with launcher.cpp
0 commit comments