-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add function to query windows known folders #31331
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that environment variables aren't the most robust things to depend on. Was the motivation real or theoretical here? (Ie, did a user actually break their julia install by messing with %SYSTEMROOT%
?)
Regarding API, this looks reasonable if it's limited to internal use by Base
. If we wanted a general "standard paths" API, we should consider looking for some API inspiration elsewhere, for example:
- QStandardPath https://doc.qt.io/qt-5/qstandardpaths.html
- PlatformFolders https://github.com/sago007/PlatformFolders
This needs some kind of tests before merging. Obviously the output of this function will depend on the test machine configuration. That's annoying but you could do some pattern matching I suppose.
pathptr = Ref{Ptr{Cwchar_t}}() | ||
result = ccall((:SHGetKnownFolderPath,:shell32), stdcall, Cint, | ||
(GUID, UInt32, Ptr{Cvoid}, Ref{Ptr{Cwchar_t}}), folderid, KF_FLAG_DEFAULT, C_NULL, pathptr) | ||
result != 0 && error() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throwing SystemError("SHGetKnownFolderPath", result)
would be more helpful here if this ever failed.
result = ccall((:SHGetKnownFolderPath,:shell32), stdcall, Cint, | ||
(GUID, UInt32, Ptr{Cvoid}, Ref{Ptr{Cwchar_t}}), folderid, KF_FLAG_DEFAULT, C_NULL, pathptr) | ||
result != 0 && error() | ||
pathbuf = unsafe_wrap(Vector{Cwchar_t}, pathptr[], ccall(:wcslen, UInt, (Ptr{Cwchar_t},), pathptr[])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wcslen
returns size_t
; best use Csize_t
for clarity.
result != 0 && error() | ||
pathbuf = unsafe_wrap(Vector{Cwchar_t}, pathptr[], ccall(:wcslen, UInt, (Ptr{Cwchar_t},), pathptr[])) | ||
path = transcode(String, pathbuf) | ||
ccall((:CoTaskMemFree, :ole32), stdcall, Cvoid, (Ptr{Cwchar_t},), pathptr[]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically this takes void*
as input.
@c42f thank you for the review and comments.
The concern here was more theoretical. My initial motivation was just to limit this to internal use in Base, although I see the benefit of a better API for standardpaths. |
Hum. If the concern is theoretical it does make me wonder how useful it is to have all this code to kill off a couple of environment variable uses which may be removed anyway (#27043). Do you have a link to the original conversation containing a bit more motivation for doing this? |
Well other packages that rely on these system paths, specifically PyCall, directly call These directories can be different from when run from msys or cygwin terminal, and environment variables may be overridden. SHGetKnownFolderPath() always gives the correct path to known system folders. There probably needs to be some more discussion on an API and how this should all look like, but I wanted to get the ball rolling with a PR. |
Oh excellent: that's good motivation to have this code if it's being duplicated across the ecosystem. (I was just a little worried that it didn't seem entirely worthwhile to clean up a couple of uses in Base.) However, I think that also means designing a public API which can be portable (to the extent possible) between systems. At a quick glance Qt's Another place to look for use cases (in addition to PyCall) would be the handling of standard paths rooted in the user home directories as used to find julia configuration, julia Pkg data, etc. How are they handled and can it be unified in a neat way under this API? |
Stale |
I put this in a package https://github.com/musm/WinKnownPaths.jl |
@c42f should we think about more general platform folder abstractions? I registered the julia package, but it might be beneficial to try to make a cross-platform version with the same idea. |
I'm just not sure if it's as a big an issue on macos and linux as windows ? |
""" | ||
function get_known_folder_path(folderid::GUID) | ||
pathptr = Ref{Ptr{Cwchar_t}}() | ||
result = ccall((:SHGetKnownFolderPath,:shell32), stdcall, Cint, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason I am unable to get this line to run on win-32bit. It keeps spitting ERROR: ReadOnlyMemoryError()
As suggested and remarked by
@stevengj
relying on environment variables for system paths can be dangerous, especially since users can mess with them.For example, an easy way to break julia's download function is as follows
In this PR we wrap windows api to access known folders from julia, to prevent such problems.