Skip to content

✨ feat(windows): use SHGetKnownFolderPath API#380

Merged
gaborbernat merged 1 commit intotox-dev:mainfrom
moi15moi:Use-SHGetKnownFolderPath
Feb 12, 2026
Merged

✨ feat(windows): use SHGetKnownFolderPath API#380
gaborbernat merged 1 commit intotox-dev:mainfrom
moi15moi:Use-SHGetKnownFolderPath

Conversation

@moi15moi
Copy link
Copy Markdown
Contributor

@moi15moi moi15moi commented Sep 7, 2025

The ctypes backend on Windows used SHGetFolderPathW, a legacy API that Microsoft has marked deprecated since Windows Vista. It relies on integer CSIDL constants and has a hard-coded MAX_PATH (260 char) buffer, which silently truncates long paths. The CSIDL_DOWNLOADS folder had no dedicated constant at all, requiring a brittle workaround that appended "Downloads" to the user profile path -- breaking for any user who relocated their Downloads folder.

🔄 This replaces it with SHGetKnownFolderPath, the modern successor that uses KnownFolder GUIDs and allocates its own buffer (no MAX_PATH limit). Every folder -- including Downloads and Desktop -- now has a proper GUID, so the CSIDL_DOWNLOADS workaround is gone. The DLL function signatures are declared with proper argtypes/restype instead of relying on the untyped ctypes.windll singleton, and the allocated memory is freed via CoTaskMemFree as required by the API contract.

The fallback chain (ctypes -> registry -> env vars) is preserved. The _pick_get_win_folder selector is simplified since ctypes.WinDLL is always available when ctypes is importable on CPython.

Fix #348

Co-authored-by: moi15moi moi15moismokerlolilol@gmail.com

@gaborbernat
Copy link
Copy Markdown
Member

gaborbernat commented Sep 8, 2025

@moi15moi you might want to take a look at the now abandoned previous attempt #350; feedback applied there will be relavant here too.

Copy link
Copy Markdown
Member

@gaborbernat gaborbernat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to fix the type checker at least 👍

@gaborbernat gaborbernat marked this pull request as draft September 8, 2025 21:43
@gaborbernat gaborbernat force-pushed the Use-SHGetKnownFolderPath branch 2 times, most recently from 6ebb0a3 to 206a824 Compare February 12, 2026 19:08
Fix tox-dev#348

Co-authored-by: moi15moi <moi15moismokerlolilol@gmail.com>
@gaborbernat gaborbernat force-pushed the Use-SHGetKnownFolderPath branch from 206a824 to 59a74be Compare February 12, 2026 19:26
@gaborbernat gaborbernat marked this pull request as ready for review February 12, 2026 19:26
@gaborbernat gaborbernat enabled auto-merge (squash) February 12, 2026 19:26
@gaborbernat gaborbernat changed the title Replace SHGetFolderPathW with SHGetKnownFolderPath ✨ feat(windows): use SHGetKnownFolderPath API Feb 12, 2026
@gaborbernat gaborbernat disabled auto-merge February 12, 2026 19:28
@gaborbernat gaborbernat merged commit 22898d3 into tox-dev:main Feb 12, 2026
26 checks passed
gaborbernat added a commit to gaborbernat/platformdirs that referenced this pull request Feb 13, 2026
SHGetKnownFolderPath with default flags (0) verifies that the target
folder physically exists, raising FileNotFoundError in sandboxed
Windows environments where USERPROFILE points to a directory without
AppData\Local. This was a regression introduced in 4.7.0 when PR tox-dev#380
replaced SHGetFolderPathW with SHGetKnownFolderPath.

Passing KF_FLAG_DONT_VERIFY (0x00004000) restores the pre-4.7.0
behavior of returning the expected path without existence checks,
matching how the old SHGetFolderPathW API worked.

Closes tox-dev#421
gaborbernat added a commit to gaborbernat/platformdirs that referenced this pull request Feb 13, 2026
SHGetKnownFolderPath with default flags (0) verifies that the target
folder physically exists, raising FileNotFoundError in sandboxed
Windows environments where USERPROFILE points to a directory without
AppData\Local. This was a regression introduced in 4.7.0 when PR tox-dev#380
replaced SHGetFolderPathW with SHGetKnownFolderPath.

Passing KF_FLAG_DONT_VERIFY (0x00004000) restores the pre-4.7.0
behavior of returning the expected path without existence checks,
matching how the old SHGetFolderPathW API worked.

Closes tox-dev#421

Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
gaborbernat added a commit to gaborbernat/platformdirs that referenced this pull request Feb 13, 2026
SHGetKnownFolderPath with default flags (0) verifies that the target
folder physically exists, raising FileNotFoundError in sandboxed
Windows environments where USERPROFILE points to a directory without
AppData\Local. This was a regression introduced in 4.7.0 when PR tox-dev#380
replaced SHGetFolderPathW with SHGetKnownFolderPath.

Passing KF_FLAG_DONT_VERIFY (0x00004000) restores the pre-4.7.0
behavior of returning the expected path without existence checks,
matching how the old SHGetFolderPathW API worked.

Closes tox-dev#421

Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
gaborbernat added a commit that referenced this pull request Feb 13, 2026
* 🐛 fix(windows): pass KF_FLAG_DONT_VERIFY to SHGetKnownFolderPath

SHGetKnownFolderPath with default flags (0) verifies that the target
folder physically exists, raising FileNotFoundError in sandboxed
Windows environments where USERPROFILE points to a directory without
AppData\Local. This was a regression introduced in 4.7.0 when PR #380
replaced SHGetFolderPathW with SHGetKnownFolderPath.

Passing KF_FLAG_DONT_VERIFY (0x00004000) restores the pre-4.7.0
behavior of returning the expected path without existence checks,
matching how the old SHGetFolderPathW API worked.

Closes #421

Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>

* test(windows): use real ctypes on Windows CI

On Windows, call get_win_folder_via_ctypes with the real Windows API for
each CSIDL name to verify integration. Reserve mock-based tests for
non-Windows where ctypes Windows bindings don't exist.

* fix(tests): resolve unused type-ignore warnings on Windows

Move ctypes.WinDLL mock assignment into _setup_ctypes_mocks so the
type: ignore comment only exists in one place that ty can reason about.

---------

Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SHGetFolderPathW is deprecated

2 participants