Skip to content

A Zig SHGetKnownFolderPath implementation in the standard library #18098

Open
@squeek502

Description

@squeek502

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.

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,
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    contributor friendlyThis issue is limited in scope and/or knowledge of Zig internals.enhancementSolving this issue will likely involve adding new logic or components to the codebase.standard libraryThis issue involves writing Zig code for the standard library.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions