Description
EDIT: This is currently being worked on here: https://github.com/squeek502/get-known-folder-path
Follow up from #18091
To avoid a dependency on shell32.dll
, the SHGetKnownFolderPath
call within std.fs.getAppDataDir
was replaced with a LOCALAPPDATA
environment variable lookup. This has the potential to regress getAppDataDir
behavior for certain setups and it's not foolproof to rely on LOCALAPPDATA
being set.
Instead, SHGetKnownFolderPath
should be reimplemented in Zig without introducing a dependency on shell32
. For this, wine
's implementation would likely be a good reference.
- wine's implementation
- Procmon csv output of the standalone program below on my computer
- https://github.com/ziglang/zig/blob/master/lib/std/fs/get_app_data_dir.zig
Standalone version of the previous implementation using SHGetKnownFolderPath
(this is ultimately the behavior that the Zig reimplementation is looking to match, but it shouldn't be FOLDERID_LocalAppData
-specific):
const std = @import("std");
const os = std.os;
pub extern "shell32" fn SHGetKnownFolderPath(
rfid: *const os.windows.KNOWNFOLDERID,
dwFlags: os.windows.DWORD,
hToken: ?os.windows.HANDLE,
ppszPath: *[*:0]os.windows.WCHAR,
) callconv(os.windows.WINAPI) os.windows.HRESULT;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer std.debug.assert(gpa.deinit() == .ok);
const allocator = gpa.allocator();
var dir_path_ptr: [*:0]u16 = undefined;
switch (SHGetKnownFolderPath(
&os.windows.FOLDERID_LocalAppData,
os.windows.KF_FLAG_CREATE,
null,
&dir_path_ptr,
)) {
os.windows.S_OK => {
const global_dir = std.unicode.utf16leToUtf8Alloc(allocator, std.mem.sliceTo(dir_path_ptr, 0)) catch |err| switch (err) {
error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
error.OutOfMemory => return error.OutOfMemory,
};
defer allocator.free(global_dir);
std.debug.print("{s}\n", .{global_dir});
},
os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
else => return error.AppDataDirUnavailable,
}
}