Open sba923 opened 4 years ago
Looks like this is because on .NET Framework, Environment.GetFolderPath()
uses ShGetFolderPath
which cannot give you the downloads folder (it has no CSIDL value). On .NET Core, perhaps to accommodate long paths, we already changed to ShGetKnownFolderPath
. This takes KNOWNFOLDERID
and Downloads has one of these.
This is essentially an API request for new members of Environment.SpecialFolders. Someone interested in this should make a list of proposed additions. Note that they ideally all have some meaning on Mac and Linux. We should not add "CameraRoll" unless it's actually important. Downloads seems pretty basic though.
If it's documented, I recommend including it since determining importance is a fool's errand. For example, CameraRoll might not be important to many, but since it is included in One Drive Known Folder Move it is of interest to people trying to use that. Definitely include
If it's documented, I recommend including it since determining importance is a fool's errand.
Maybe if Windows was the only relevant OS, but it is not: as the list gets longer there are more entries without clear mappings on various Linux distros, macOS, Android, iOS, etc. We can take guesses or return empty string but that potentially makes life harder for folks trying to target those OS, who must now figure out which members of the enumeration are going to be useful. Eg., what should CameraRoll return on Ubuntu? Maybe there is no mapping, or several possible mappings. If I'm writing a photo editor app, should I offer it in my "open file" picker?
We are already returning empty string in quite a few cases for Unix https://github.com/dotnet/runtime/blob/2d4acbde200dba78794d9baf8cc69c170267fde0/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs#L143
And for example on about 30 cases on iOS https://github.com/mono/mono/blob/c5b88ec4f323f2bdb7c7d0a595ece28dae66579c/mcs/class/corlib/System/Environment.iOS.cs#L91
Sure, Windows is not the only targeted OS. I'm a great advocate of non-Windows .NET Core / PowerShell.
But OTOH, not all code / scripts is / are written to be xplat!
I hate that I have to write weird code (mainly on Windows) to determine where the Downloads folder resides...
It would be good to improve the doc so it has a big table showing what works on what platform. It looks like it's not been updated for cross plat.
https://docs.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=netcore-3.1
Yes! And that big table would have Windows-only entries ;-) Or "not MacOS" entries. Whatever.
Per #57133, we should consider the Saved Games folder as a candidate too.
In the interest of pushing this forward I've put together a spreadsheet of all the KnownFolderIds that are missing, as well as whether they're usable on *nix or mac.
What I don't have is a good way to collaborate on these, as I'm not a mac or *nix user so I'm not sure what the sane defaults would be.
(read-only view of the spreadsheet) https://1drv.ms/x/s!Aqd0GRdPyzYske0aoWS8kUiTamIu7A?e=bBfntf
One thing that struck me as a bit odd while I was working on this is that MyComputer is a valid SpecialFolder. This is the only KnownFolderId which is marked as a Virtual folder, and I don't think it will EVER return a valid path on Windows.
This seems to be the newest discussion on this topic. I got my feet wet and tried implementing the "Downloads" and "Public" folder with these paths, given they seem requested the most:
Folder | Linux1 | macOS2 | iOS2 | Windows3 |
---|---|---|---|---|
Downloads | XDG_DOWNLOAD_DIR or <home>/Downloads |
<home>/Downloads |
<personal>/Downloads |
FOLDERID_Downloads |
Public | XDG_PUBLICSHARE_DIR or <home>/Public |
<home>/Public |
- | FOLDERID_Public 4 |
1 Judging from existing code and https://wiki.archlinux.org/title/XDG_user_directories 2 Judging from existing code and screenshots (I do not own Apple hardware) 3 https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid 4 This path is the same for all users on Windows. Unlike Linux and macOS, there is no user-specific Public folder on Windows.
I noticed some things while doing so:
System.Environment.SpecialFolder
enum uses Windows' deprecated CSIDL values. To add non-CSIDL folder values, I started the new values at 0x10000
as it is larger than any possible CSIDL value. This shouldn't be too much of an issue as the enum uses the default underlying type of int
which remains unchanged.MyDownloads
in the style of MyDocuments
, MyPictures
, and MyVideos
- I recall Windows 7 reintroducing the "My" prefix after it was dropped in Vista, but I don't remember if this was the case for the Downloads folder tooDownloads
(it never used a "My" prefix as I originally thought, and this would match the native FOLDERID_Downloads
aswell).PublicDirectory
in the style of DesktopDirectory
and CommonDesktopDirectory
, as Public
is a reserved keyword in VB.NET, despite this no longer matching the native FOLDERID_Public
definition. The GUID string constant in Interop.Shell32.KnownFolders
is still named Public
to match the native declaration and seems used by internal C# code only.SpecialFolder.MyVideos
seems incorrect on OSX as the macOS user folder is named Movies
and not Videos
. Are XDG
variables even defined in macOS, the preprocessor block below seems to state the opposite? Impossible to change now without breaking the behavior of existing apps, and offtopic for this issue.SpecialDirectories
, though its properties do not even cover the existing SpecialFolder
enum and were probably just meant for "portability" from original VB6 code.I did not tackle the "Saved Games" folder as only Windows has it, and the discussion went into the direction of focusing folders that have viable cross-platform paths first.
If you are interested, I can write an API Proposal to add these two folders. Wanted to hear some feedback on this existing issue first :-)
I named the new enum value for the "Downloads" folder MyDownloads in the style of MyDocuments, MyPictures, and MyVideos - I recall Windows 7 reintroducing the "My" prefix after it was dropped in Vista, but I don't remember if this was the case for the Downloads folder too.
On my Windows 7 VM, only Documents, Music, Pictures, and Videos have the My prefix. (Matches https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid)
. Are XDG variables even defined in macOS, the preprocessor block below seems to state the opposite
I don't have a Mac but I don't believe so. If Macs have a "movies" folder then we should implement it to return that for SpecialFolders.MyVideos. That's just a bug fix -- https://github.com/dotnet/runtime/issues/68323
BTW, I found https://github.com/dotnet/runtime/issues/25577 and https://github.com/dotnet/runtime/issues/63214 -- lots of discussion here, as no maintainers like me have sat down and organized.
I wouldn't bother to add to the VB enum as you point out.
It would be great to open an API proposal for those two, and any others you believe (based on all these discussions) seem to make general sense. Perhaps we can end up closing all these issues..
BTW @RayKoopa thanks for reviving this. And @AtomicBlom for the spreadsheet, which I pasted here in case it gets lost. https://gist.github.com/danmoseley/edb3708c1bacc2998890e44e7ea4e4d4
Thank you for checking on the folder names and other discussions.
I'm still sorting my notes a bit from the many comments written throughout the years, but have updated mine above (which I slightly use as my blueprint for an API proposal):
SpecialFolder.Downloads
, not SpecialFolder.MyDownloads
MyVideo
folder bug on macOS (together with some others).SpecialDirectories
class.For simplicity, at the moment I'd prefer to only focus on the "missing user folders" common to Linux / macOS / Windows, e.g. "Downloads" and "Public" (despite the latter not being a user-specific folder on Windows, but I think that is neglectible since everyone has access to it by default).
BTW @RayKoopa thanks for reviving this. And @AtomicBlom for the spreadsheet, which I pasted here in case it gets lost. https://gist.github.com/danmoseley/edb3708c1bacc2998890e44e7ea4e4d4
Thanks for saving the spreadsheet.
Shouldn't it include a column indicating what is currently supported by .NET (might even depen on version?)?
Phew, I've now dug through related issues, PRs and API proposals.
They currently block me moving forward with my blueprint above as they make valid points in that extending the enum may not be a good idea. However, I cannot rate how important the points made are today:
SpecialFolder
, first mention of new (but internal) GUID based APISpecialFolder
API in favor of a new, public GUID based API:SpecialFolder
enum in any way would break code assuming it maps to deprecated Windows' CSIDLsSpecialFolder
againSpecialFolder
againSpecialFolder
againSo either
What do? 🤔
I would honestly like to see a short-term fix in place for at least the user folders.
I stumbled across and became invested in this task after I became aware of how few developers were making use of the "Saved Games" folder in windows, and many games scatter their saved games everywhere across local app data, roaming app data, my documents, etc. All this means that for games that don't cloud save, it's very difficult to back them all up
I wanted to make sure that my games used what I perceive to be the best location for them, and I want to promote that there is a location for saved games, However the Enum value doesn't work for non-windows platforms, so it's back to square one.
I would honestly like to see a short-term fix in place for at least the user folders.
Me too. The only "real" reason against short-term extending the enum because "code assuming it maps to Windows' CSIDLs would break" is valid but exotic. What would be a use case for that? Any code doing this...
I became aware of how few developers were making use of the "Saved Games" folder in windows
However the Enum value doesn't work for non-windows platform
These two reasons actually made me exclude the "Saved Games" in an API Proposal I'd write so far, and only focus on the more commonly requested "Downloads" and "Public" first - unless maintainers are okay with "Saved Games" returning "yet another" String.Empty
on Linux and macOS. Would definitely make .NET more inviting for game developers given the almost nonexistant adoption of this folder after Vista used it for Purble Place etc. :-)
This seems to be the newest discussion on this topic. I got my feet wet and tried implementing the "Downloads" and "Public" folder with these paths, given they seem requested the most:
Just wanted to leave a quick note, that the public directory functions a little differently between Windows and Linux/MacOS. On Windows, there only exists one public folder which every user has access to. On Linux/MacOS, every user has it's own public folder that the other users can access. This should get documented, just so that developers are aware of it.
Also, this may just be a thing that's unclear due to it being short, but for the Linux assignments, it shouldn't be an "or", rather a "fallback" should the former variable not exist. If you're using ReadXdgDirectory
then it's already handled for you there.
Yes, I've mentioned this in the "foot"notes under the table, footnote 4 specifically. Indeed 'or' is just to save space in the table, I linked to the existing code in footnote 1.
If improvements were to ship in the next version of .NET, which Windows version would be the oldest to receive that .NET version by default?
I maintain a library that starts a new process, runs PowerShell, throws
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\n" +
"Add-Type @\"\n" +
"using System;\n" +
"using System.Runtime.InteropServices;\n" +
"public class Dir {\n" +
" [DllImport(\"shell32.dll\")]\n" +
" private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr pszPath);\n" +
" public static string GetKnownFolderPath(string rfid) {\n" +
" IntPtr pszPath;\n" +
" if (SHGetKnownFolderPath(new Guid(rfid), 0, IntPtr.Zero, out pszPath) != 0) return \"\";\n" +
" string path = Marshal.PtrToStringUni(pszPath);\n" +
" Marshal.FreeCoTaskMem(pszPath);\n" +
" return path;\n" +
" }\n" +
"}\n" +
"\"@\n"
over the fence, hopes for the best and parses the response.
Reliability has been a consistent issue with this and a better replacement would be appreciated, but I wonder how long improvements will take until I can actually use it.
If improvements were to ship in the next version of .NET, which Windows version would be the oldest to receive that .NET version by default?
According to MSDN the current .NET 6 supports Windows 7 / Server 2012 and newer. But I can't tell you if Windows 7 is planned to be dropped in .NET 7 / 8 / whenever this feature will make the cut.
That means Windows Vista and Server 2008 (R2) would be the only systems not prospering from the special folders added here, and would also be the only systems even having these folders and the API to query them.
Reliability has been a consistent issue with this and a better replacement would be appreciated, but I wonder how long improvements will take until I can actually use it.
Apparently offtopic here, but can you explain why it isn't working reliably for you? In effect, it is imported and called by .NET like you do (minus the automatic string marshaling).
@RayKoopa
Windows Vista and Server 2008 (R2) would be the only systems not prospering from the special folders added here
Interesting, thanks!
can you explain why it isn't working reliably for you
I went through all issues and tagged Windows-specific issues for better visibility, hope this helps.
It ranges from the mundane "Add-Type
failed because some other application messed with LIB
" to hilarious things like having to downgrade PowerShell to v2.0 to evade Constrained Language Mode
restrictions.
Basically 60% of the project's bugs are "Windows not working for someone", despite Windows probably only being used by a minority of users.
But I can't tell you if Windows 7 is planned to be dropped in .NET 7 / 8 / whenever this feature will make the cut.
I can't offer an official word, but I know of no plans to drop Windows 7 support in .NET 7 given it remains in extended support until 2023
Hey @danmoseley, thanks for the info!
Just to check that we are on the same page – does this mean that on Windows 7 (and later) one can expect .NET 7 to be installed after its release?
Another thing just crossed my mind... exposing the "Public" folder on Windows may not be sufficient or even meaningful.
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.PublicDirectory, "Pictures")
...So if SpecialFolder.Public(Directory)
should be introduced, so should be the specific child folders as PublicPictures
, PublicDownloads
, etc.. And they would return String.Empty
on Unix.
I can't offer an official word, but I know of no plans to drop Windows 7 support in .NET 7
The list of OS versions that we expected to support for .NET 7 is documented in https://github.com/dotnet/core/blob/main/release-notes/7.0/supported-os.md
does this mean that on Windows 7 (and later) one can expect .NET 7 to be installed after its release?
.NET 5+ is not part of Windows and it is not automatically installed by Windows. You have to either install it on the machine yourself or you can bundle the runtime with the app by publishing it as self-contained.
@jkotas
.NET 5+ is not part of Windows and it is not automatically installed by Windows.
Oh, welp. So improvements made in this issue won't be of any help for my use-case then. :-/
You have to either install it on the machine yourself or you can bundle the runtime with the app by publishing it as self-contained.
The library I'm maintaining is around 7kB and included with other people's applications. Bundling a whole .NET install with it is completely out of question.
It's 2022 and it's not possible to retrieve Windows' special folders in an architecture-independent way? Am I missing something?
The library I'm maintaining is around 7kB and included with other people's applications. Bundling a whole .NET install with it is completely out of question.
It's 2022 and it's not possible to retrieve Windows' special folders in an architecture-independent way? Am I missing something?
.NET does not have an API to retrieve "newer" (Vista+ though) special folders like the ones mentioned here - e.g. "Downloads" and "Public" being ones you are asking for, judging from your project (my recent comment on the "Public" folder may be of interest aswell).
It will internally just call the WinAPI method SHGetKnownFolderPath
that is available since Vista, just like you already do via PowerShell. The issues you described above have to do with PowerShell, not the call itself. In your case I'd recommend calling it with JNI / C, to prevent having to skip through additional execution layers (effectively layers that may cause problems).
We may want to talk about this in detail on your project's issue as it's slightly offtopic here (feel free to ping me and I add what I know :-) )
Before this stales away again, should I push ahead and make an API proposal as I outlined above? To recap:
🟢 Extend SpecialFolder
starting at value 0x10000
with folders commonly available cross-platform:
SpecialFolder | macOS | iOS | Linux (with XDG) | Linux | Windows |
---|---|---|---|---|---|
Downloads | ~/Downloads | NSDocumentDirectory/Downloads | XDG_DOWNLOAD_DIR | ~/Downloads | FOLDERID_Downloads |
PublicDirectory | ~/Public | - | XDG_PUBLICSHARE_DIR | ~/Public | FOLDERID_Public |
PublicDesktop | - | - | - | - | FOLDERID_PublicDesktop |
PublicDocuments | - | - | - | - | FOLDERID_PublicDocuments |
PublicDownloads | - | - | - | - | FOLDERID_PublicDownloads |
PublicMusic | - | - | - | - | FOLDERID_PublicMusic |
PublicVideos | - | - | - | - | FOLDERID_PublicVideos |
SavedGames | - | - | - | - | FOLDERID_SavedGames |
Reasoning:
0x10000
due to the undocumented fact that the existing values map to Windows' CSIDL
s, and 0x10000
is the first invalid CSIDL
combination.
CSIDL
API is deprecated, not used by .NET anymore, and does not allow querying the folders above anyway.SpecialFolder
via reflection and / or using those values for actual CSIDL
s means.~
is the home directory as it is already determined.XDG...
variables are used on Linux if they exist, otherwise the non-XDG path is used as a fallback.
Public
folder is named PublicDirectory
to not clash with keywords (e.g. VB.NET).
Public...
sub folders is required for Windows as they may be redirected outside of the parent PublicDirectory
. Otherwise it could lead to developers looking for them to incorrectly hardcode parts of their path again by assuming they are children (the same issue currently with the Downloads and Public folders themselves).SavedGames
is included as it is the only remaining Windows user folder meaningful to developers. The others I do not recommend adding as they have a very special meaning only to one Windows app / component:
SpecialFolder | Windows only | Used by / meant for |
---|---|---|
❌ Contacts | FOLDERID_Contacts | Windows Contacts contact files. |
❌ Links | FOLDERID_Links | File Explorer pinned location shortcut files (< Windows 10 only). |
❌ Searches | FOLDERID_Searches | Parameterized Windows Search query files. |
For consistency, the following two breaking changes already mentioned in https://github.com/dotnet/runtime/issues/63214 should be proposed aswell:
🟠 Change SpecialFolder.MyDocuments
on Unix to point to the actual "Documents" sub folder, not the home directory:
Behavior | macOS | iOS | Linux (with XDG) | Linux |
---|---|---|---|---|
Current | ~ | NSDocumentDirectory | ~ | ~ |
Proposed | ~/Documents | NSDocumentDirectory | XDG_DOCUMENTS_DIR | ~/Documents |
🟠 Change SpecialFolder.MyVideos
to point to macOS' "Movies" folder as it does not actually have a "Videos" folder:
Behavior | macOS | iOS |
---|---|---|
Current | ~/Videos | NSDocumentDirectory/Videos |
Proposed | ~/Movies | NSDocumentDirectory/Movies |
This has already been started just recently here: https://github.com/dotnet/runtime/pull/68610. I will wait on the acceptance / merge of that PR first before continuing with the new folder proposal to prevent clashes / confusion.
Linking https://github.com/dotnet/runtime/pull/68610 here as well...
Thanks for letting me know. I crossed out the breaking changes in my recap that are already started there and wait for the outcome of the PR / discussions first.
This looks reasonable, but I want to ask for clarification regarding the public subfolders on Linux:
Are the subfolder names fixed to the values mentioned above or are the translated values of the personal download/music/document/... folders used?
Sadly those folders are locale-dependent (seemingly every OS needs to make that mistake at least once) and in my opinion using a fixed language for public subdirs would be wrong:
If XDG_DOWNLOAD_DIR
was /home/me/Heruntergeladenes
, then PublicDownloads
should be /home/soc/Öffentlich/Heruntergeladenes
, not /home/soc/Öffentlich/Downloads
.
So XDG_PUBLICSHARE_DIR/Downloads
should be something like XDG_PUBLICSHARE_DIR/last-path-component(XDG_DOWNLOAD_DIR)
to avoid English folder names on non-English systems.
Thanks for opening the discussion on that.
I included the paths returned on Unix based on the currently used fallback names, and only added them for "convenience". But I also share the decision to not return a path at all for them since they simply don't exist in Unix, and cannot be retrieved in any meaningful way:
xdg-user-dirs-update
, which translates the keys specified in /etc/xdg/user-dirs.defaults
for each folder with the language set in ~/.config/user-dirs.locale
, but I don't know how to query the translations like xdg-user-dirs-update
does (in a way that would be reasonable while querying a folder path). And then I'm only talking about Ubuntu 22.04 here, not any other distro.So if you ask me, either use hardcoded English names, or not return any paths for these folders on Unix. For simplicity and comparable behavior to other folders not supported on a system, I'd even prefer not returning a path.
@RayKoopa
I don't know how to query the translations like xdg-user-dirs-update does
That's exactly what ReadXdgDirectory
does – there is no need for anything beyond what's already implemented.
redirecting all his sub folders to just his home when he doesn't like them
I think this is already spelled out in the spec. There is no reason why subdirs should behave differently.
expose names in a shared folder which nobody should see
That's a good point!
or not return any paths for these folders on Unix
That also sounds fine to me.
That's exactly what
ReadXdgDirectory
does – there is no need for anything beyond what's already implemented.
ReadXdgDirectory
queries a full user folder path, not the system's translation for a folder name to be appended to the public folder. As mentioned, the user folder path cannot be processed in any way for that.
Agree here that the public subfolders should rather not return anything at all on Linux.
For consistency's sake, should MacOS not return anything for those subfolder as well then? Since they also technically do not exist there, and from what I understand from the docs they'd rather have only Users use those. Not to mention that those folders are translated in MacOS. Not via naming, but by having a .localized
in the folder which the file explorer will then use to show a localized name of that folder. I.e. from Documents
to Dokumente
. Having suddenly English-named folders in a non-English environment would be a little weird, which could get mitigated by .NET always creating that .localized
file, but that sounds like it'd create even more issues.
Yeah, whenever I mentioned "Unix", I meant both macOS and Linux. And I agree, adding exceptionally much magic for determining these folder's names or getting them localized is not meaningful here.
After this discussion and my own personal reconsideration, I updated my recap to return empty paths on those systems. After all, the reason the public subfolders were added was only because they are important on Windows. :-)
EDIT: Now my last bullet "Other "special" folders (like Windows' "Saved Games" or "Public Desktop") are not included due to them having no meaningful cross-platform counterpart." looks a little dumb. I could just aswell add those folders for Windows-only now.
Links | Stores Explorer pinned location shortcut files on < Windows 10.
Considering that Win7 is now EOL, with there only coming security updates, and everything before already being not supported, is this really worth adding?
Probably not - yet Windows 7 is still in extended support, and apparently going to be supported in .NET 7. I don't know about the support periods of Windows 8 right now but would assume they're longer. According to just this it would be better to add it.
However, the only use-case I could think of is someone designing their own OpenFileDialog or wanting to display user favorites - but they'd need special logic for Windows 10 anyway as it uses a different storage for managing "Quick Access". The Links folder still exists in Windows 10 but has no real use anymore IIRC (I think I actually deleted mine completely...).
EDIT: I rated this use case as quite exotic and moved that folder to ❌.
You also might wanna include the PublicDesktop to the big table as well, since it's just another public subfolder.
NVM just remembered that PublicDesktop serves a different function
You're actually right, it should be in there given "Desktop" by itself is a common user folder on all systems, which I forgot. Adjusted my comment.
Behavior macOS iOS Current ~/Videos ~/Videos Proposed ~/Movies ~/Movies
I honestly have no idea about anything iOS related, but from I've seen, file system access is very limited. The current iOS bindings for example return <DocumentsFolder>/Movies
<DocumentsFolder>/Videos
instead.
I don't have an iPhone or iOS emulator here too, so I wonder if a participant of this discussion could check for the existence of either "Movies" or "Videos" on a relatively clean device / installation.
The current iOS bindings for example return
<DocumentsFolder>/Movies
instead.
To me that line of code looks like ~/Videos
though, I understood your comment as ~/Documents/Movies
.
To me that line of code looks like
~/Videos
though, I understood your comment as~/Documents/Movies.
Last part was a typo, meant <DocumentsFolder>/Videos
instead.
Look at: Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");
. Quick reminder that Personal is the same as MyDocuments. Aka, this returns <DocumentsFolder>
+ Videos
.
It should probably be still changed to <DocumentsFolder>/Movies
tho, just to keep it consistent.
I also used <DocumentsFolder>
here for a reason since it's very likely not in ~/Documents
. Personal is called via NSDocumentDirecctory so this'll likely return the documents folder inside the sandboxed iOS app.
Just realized, that this also means that the iOS part in your Documents table is wrong as well. The Documents entry on iOS, from what I can see, doesn't need any updating at all.
Look at:
Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");
. Quick reminder that Personal is the same as MyDocuments.
Right, I thought SpecialFolder.Personal
is SpecialFolder.UserProfile
(since that's what it always sounded like). Sorry about the confusion.
But I'm getting a bit more confused now, please let me know if I understood correctly:
NSMoviesDirectory
, NSMusicDirectory
etc, the user folder paths are at ~/Movies
, ~/Music
etc. as shown in my table above.SpecialFolder.MyDocuments
&SpecialFolder.Personal
to return what would be NSDocumentDirectory
/ ~/Documents
, then the code you linked to needs fixing and should use SpecialFolder.UserProfile
instead of SpecialFolder.Personal
.~/Music
to ~/Documents/Music
that don't exist at all, have no meaning on the platform, and break existing applications.Just realized, that this also means that the iOS part in your Documents table is wrong as well. The Documents entry on iOS, from what I can see, doesn't need any updating at all.
Understood and adjusted. Didn't expect the iOS code to be like "that" :-)
Given NSMoviesDirectory, NSMusicDirectory etc, the user folder paths are at ~/Movies, ~/Music etc. as shown in my table above.
You need to differentiate here between iOS and MacOS.
In iOS, the NSDirectories are from what I can see never actually invoked except for NSDocumentsDirectory
. In the file I linked, all the user folder paths redirect to <DocumentsFolder>/<UserFolder>
instead of the filesystem one, due to the way iOS apps are sandboxed. NSDocumentsDirectory
is also a different path from HOME
.
On MacOS, while the NSDirectories are also never invoked, it (almost) returns the same directories as them. So yes.
If you fix SpecialFolder.MyDocuments&SpecialFolder.Personal to return what would be NSDocumentDirectory / ~/Documents, then the code you linked to needs fixing and should use SpecialFolder.UserProfile instead of SpecialFolder.Personal.
Nope, the way it is right now is intended. The UNIX changes do not affect iOS; iOS already invokes NSDocumentsDirectory
for Personal
/MyDocuments
and checks HOME
for UserProfile
. And again, it uses NSDocumentsDirectory
because of iOS apps are all sandboxed.
Otherwise you would change the path to user folders like ~/Music to ~/Documents/Music that don't exist at all, have no meaning on the platform, and break existing applications.
Sorry, I don't get quite what you're meaning with this.
If you're confused about the sandboxing and haven't looked at the doc I linked above:
For security purposes, an iOS app’s interactions with the file system are limited to the directories inside the app’s sandbox directory. [...] An app is generally prohibited from accessing or creating files outside its container directories.
In other words, no access to HOME
, hence why all iOS folders instead point to their specifically designed directories.
If I understood correctly, this means iOS apps have no way of accessing the ~/Music
folders etc., and there's only a ~/Documents
folder which is seen as the "user root folder"? Which is why the only way to retrieve a custom "Music" folder would be in ~/Documents/Music
?
NSDocumentsDirectory
!= ~/Documents/
for iOS.
All programs on iOS are their own little folder, similar to an AppImage on Linux if you've ever dealt with those. So it points more to <wherever iOS stores apps>/MyApp/Documents/
as seen here:
this means iOS apps have no way of accessing the ~/Music folders etc.
It seems possible to do via NSSearchPathDirectory.NSMusicDirectory
(or for the Apple docs here). I assume the reason why .NET links to local sandboxed folders instead is because unless there's a specific need to, apps shouldn't just break out of their sandbox. The docs for example never even mention anything iOS filesystem related outside of the sandbox:
users of iOS devices do not have direct access to the file system and apps are expected to follow this convention.
Okay, understood. Logically I'll just stay inside the sandboxed folders like .NET already does then, adding the Downloads
folder like so:
return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Downloads");
I hope my iOS columns in my recap above are now correct at least.
(Redirecting from (https://github.com/PowerShell/PowerShell/issues/11240))
It should be possible to retrieve the location of all "special folders" instead of hardcoding them (or assuming they are just subfolders of the user's profile folder).
As of today,
Environment.GetFolderPath()
(which reportedly relies on SHGetKnownFolderPath()) doesn't support all KNOWNFOLDERID's. Here's a few of the ones that are not supported:This piece of code
outputs only this subset of folder paths: