Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Private Function

findViaRegistry

Private Function
std.zig.WindowsSdk.MsvcLibDir.findViaRegistry
fn findViaRegistry(
        gpa: Allocator,
        io: Io,
        arch: std.Target.Cpu.Arch,
        environ_map: *const Environ.Map,
    ) error

Params

File

zig/WindowsSdk.zig:927
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
    fn findViaRegistry(
        gpa: Allocator,
        io: Io,
        arch: std.Target.Cpu.Arch,
        environ_map: *const Environ.Map,
    ) error{ OutOfMemory, PathNotFound }![]const u8 {
        // %localappdata%\Microsoft\VisualStudio\
        // %appdata%\Local\Microsoft\VisualStudio\
        const local_app_data_path = std.zig.EnvVar.LOCALAPPDATA.get(environ_map) orelse return error.PathNotFound;
        const visualstudio_folder_path = try Dir.path.join(gpa, &.{
            local_app_data_path, "Microsoft\\VisualStudio\\",
        });
        defer gpa.free(visualstudio_folder_path);

        if (!Dir.path.isAbsolute(visualstudio_folder_path)) return error.PathNotFound;
        // To make things easier later on, we open the VisualStudio directory here which
        // allows us to pass relative paths to NtLoadKeyEx in order to avoid dealing with
        // conversion to NT namespace paths.
        var visualstudio_folder = Dir.openDirAbsolute(io, visualstudio_folder_path, .{
            .iterate = true,
        }) catch return error.PathNotFound;
        defer visualstudio_folder.close(io);

        const vs_versions: []const []const u8 = vs_versions: {
            // enumerate folders that contain `privateregistry.bin`, looking for all versions
            // f.i. %localappdata%\Microsoft\VisualStudio\17.0_9e9cbb98\
            var iterator = visualstudio_folder.iterate();
            break :vs_versions try iterateAndFilterByVersion(&iterator, gpa, io, "");
        };
        defer {
            for (vs_versions) |vs_version| gpa.free(vs_version);
            gpa.free(vs_versions);
        }
        var key_path_buf: [windows.NAME_MAX * 2]u16 = undefined;
        var sub_path_buf: [windows.NAME_MAX * 2]u16 = undefined;
        const source_directories: []const u8 = source_directories: for (vs_versions) |vs_version| {
            const sub_path = blk: {
                var buf: std.ArrayList(u16) = .initBuffer(&sub_path_buf);
                buf.items.len += std.unicode.wtf8ToWtf16Le(buf.unusedCapacitySlice(), vs_version) catch unreachable;
                buf.appendSliceAssumeCapacity(L("\\privateregistry.bin"));
                break :blk buf.items;
            };

            // The goal is to emulate advapi32.RegLoadAppKeyW with a direct call
            // to NtLoadKeyEx instead.
            //
            // RegLoadAppKeyW loads the hive into a registry key of the format:
            // \REGISTRY\A\{fdb2baa5-8ca8-ef03-78d0-3b1f868fd2a9}
            // where `\REGISTRY\A` is a special unenumerable location intended for
            // per-app hives, and the GUID is randomly generated (in testing, it
            // was different for each run of the program).
            //
            // The OS is responsible for cleaning up `\REGISTRY\A` whenever all handles
            // to one of its keys are closed, so we don't have to do anything special
            // with regards to that.

            const temp_key_path = blk: {
                var guid: windows.GUID = undefined;
                io.random(std.mem.asBytes(&guid));

                var guid_buf: [38]u8 = undefined;
                const guid_str = std.mem.print(&guid_buf, "{f}", .{guid}) catch unreachable;

                var buf: std.ArrayList(u16) = .initBuffer(&key_path_buf);
                buf.appendSliceAssumeCapacity(L("\\REGISTRY\\A\\"));
                buf.items.len += std.unicode.wtf8ToWtf16Le(buf.unusedCapacitySlice(), guid_str) catch unreachable;
                break :blk buf.items;
            };

            const target_key: windows.OBJECT.ATTRIBUTES = .{
                .RootDirectory = null,
                .Attributes = .{},
                .ObjectName = @constCast(&windows.UNICODE_STRING.init(temp_key_path)),
                .SecurityDescriptor = null,
            };
            const source_file: windows.OBJECT.ATTRIBUTES = .{
                .RootDirectory = visualstudio_folder.handle,
                .Attributes = .{},
                .ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path)),
                .SecurityDescriptor = null,
            };
            var root_key: Registry.Key = undefined;
            const rc = windows.ntdll.NtLoadKeyEx(
                &target_key,
                &source_file,
                .{
                    .APP_HIVE = true,
                    // This wasn't set by RegLoadAppKeyW, but it seems relevant
                    // since we aren't intending to do any modifcation of the hive.
                    .OPEN_READ_ONLY = true,
                },
                null,
                null,
                .{ .SPECIFIC = .{
                    .KEY = .{
                        .QUERY_VALUE = true,
                        .ENUMERATE_SUB_KEYS = true,
                    },
                } },
                &root_key.handle,
                null,
            );
            switch (rc) {
                .SUCCESS => {},
                else => continue,
            }
            defer root_key.close();

            const config_path = blk: {
                var buf: std.ArrayList(u16) = .initBuffer(&key_path_buf);
                buf.appendSliceAssumeCapacity(L("Software\\Microsoft\\VisualStudio\\"));
                buf.items.len += std.unicode.wtf8ToWtf16Le(buf.unusedCapacitySlice(), vs_version) catch unreachable;
                buf.appendSliceAssumeCapacity(L("_Config"));
                break :blk buf.items;
            };
            const config_key = root_key.open(config_path) catch continue;

            const source_directories_value = config_key.getString(gpa, .{ .name = L("Source Directories") }, .wtf8) catch |err| switch (err) {
                error.OutOfMemory => |e| return e,
                else => continue,
            };

            break :source_directories source_directories_value;
        } else return error.PathNotFound;
        defer gpa.free(source_directories);

        var source_directories_split = std.mem.splitScalar(u8, source_directories, ';');

        const msvc_dir: []const u8 = msvc_dir: {
            const msvc_include_dir_maybe_with_trailing_slash = try gpa.dupe(u8, source_directories_split.first());

            if (msvc_include_dir_maybe_with_trailing_slash.len > Dir.max_path_bytes or !Dir.path.isAbsolute(msvc_include_dir_maybe_with_trailing_slash)) {
                gpa.free(msvc_include_dir_maybe_with_trailing_slash);
                return error.PathNotFound;
            }

            var msvc_dir = std.array_list.Managed(u8).fromOwnedSlice(gpa, msvc_include_dir_maybe_with_trailing_slash);
            errdefer msvc_dir.deinit();

            // String might contain trailing slash, so trim it here
            if (msvc_dir.items.len > "C:\\".len and msvc_dir.last().? == '\\') _ = msvc_dir.pop();

            // Remove `\include` at the end of path
            if (std.mem.endsWith(u8, msvc_dir.items, "\\include")) {
                msvc_dir.shrinkRetainingCapacity(msvc_dir.items.len - "\\include".len);
            }

            try msvc_dir.appendSlice("\\Lib\\");
            try msvc_dir.appendSlice(switch (arch) {
                .thumb => "arm",
                .aarch64 => "arm64",
                .x86 => "x86",
                .x86_64 => "x64",
                else => unreachable,
            });
            const msvc_dir_with_arch = try msvc_dir.toOwnedSlice();
            break :msvc_dir msvc_dir_with_arch;
        };
        errdefer gpa.free(msvc_dir);

        if (!verifyLibDir(io, msvc_dir)) {
            return error.PathNotFound;
        }

        return msvc_dir;
    }