mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Merge pull request #19926 from squeek502/windows-sdk-cachepath-registry
WindowsSdk: Fix finding the _Instances directory when it's not in the default location
This commit is contained in:
parent
52150b701c
commit
6ce3c2423e
@ -23,7 +23,7 @@ pub fn find(allocator: std.mem.Allocator) error{ OutOfMemory, NotFound, PathTooL
|
|||||||
if (builtin.os.tag != .windows) return error.NotFound;
|
if (builtin.os.tag != .windows) return error.NotFound;
|
||||||
|
|
||||||
//note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed
|
//note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed
|
||||||
const roots_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, windows_kits_reg_key) catch |err| switch (err) {
|
const roots_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, windows_kits_reg_key, .{ .wow64_32 = true }) catch |err| switch (err) {
|
||||||
error.KeyNotFound => return error.NotFound,
|
error.KeyNotFound => return error.NotFound,
|
||||||
};
|
};
|
||||||
defer roots_key.closeKey();
|
defer roots_key.closeKey();
|
||||||
@ -137,11 +137,17 @@ fn iterateAndFilterByVersion(
|
|||||||
return dirs.toOwnedSlice();
|
return dirs.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OpenOptions = struct {
|
||||||
|
/// Sets the KEY_WOW64_32KEY access flag.
|
||||||
|
/// https://learn.microsoft.com/en-us/windows/win32/winprog64/accessing-an-alternate-registry-view
|
||||||
|
wow64_32: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
const RegistryWtf8 = struct {
|
const RegistryWtf8 = struct {
|
||||||
key: windows.HKEY,
|
key: windows.HKEY,
|
||||||
|
|
||||||
/// Assert that `key` is valid WTF-8 string
|
/// Assert that `key` is valid WTF-8 string
|
||||||
pub fn openKey(hkey: windows.HKEY, key: []const u8) error{KeyNotFound}!RegistryWtf8 {
|
pub fn openKey(hkey: windows.HKEY, key: []const u8, options: OpenOptions) error{KeyNotFound}!RegistryWtf8 {
|
||||||
const key_wtf16le: [:0]const u16 = key_wtf16le: {
|
const key_wtf16le: [:0]const u16 = key_wtf16le: {
|
||||||
var key_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined;
|
var key_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined;
|
||||||
const key_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(key_wtf16le_buf[0..], key) catch |err| switch (err) {
|
const key_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(key_wtf16le_buf[0..], key) catch |err| switch (err) {
|
||||||
@ -151,7 +157,7 @@ const RegistryWtf8 = struct {
|
|||||||
break :key_wtf16le key_wtf16le_buf[0..key_wtf16le_len :0];
|
break :key_wtf16le key_wtf16le_buf[0..key_wtf16le_len :0];
|
||||||
};
|
};
|
||||||
|
|
||||||
const registry_wtf16le = try RegistryWtf16Le.openKey(hkey, key_wtf16le);
|
const registry_wtf16le = try RegistryWtf16Le.openKey(hkey, key_wtf16le, options);
|
||||||
return .{ .key = registry_wtf16le.key };
|
return .{ .key = registry_wtf16le.key };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,15 +245,17 @@ const RegistryWtf16Le = struct {
|
|||||||
pub const value_name_max_len = 16_383;
|
pub const value_name_max_len = 16_383;
|
||||||
|
|
||||||
/// Under HKEY_LOCAL_MACHINE with flags:
|
/// Under HKEY_LOCAL_MACHINE with flags:
|
||||||
/// KEY_QUERY_VALUE, KEY_WOW64_32KEY, and KEY_ENUMERATE_SUB_KEYS.
|
/// KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, optionally KEY_WOW64_32KEY.
|
||||||
/// After finishing work, call `closeKey`.
|
/// After finishing work, call `closeKey`.
|
||||||
fn openKey(hkey: windows.HKEY, key_wtf16le: [:0]const u16) error{KeyNotFound}!RegistryWtf16Le {
|
fn openKey(hkey: windows.HKEY, key_wtf16le: [:0]const u16, options: OpenOptions) error{KeyNotFound}!RegistryWtf16Le {
|
||||||
var key: windows.HKEY = undefined;
|
var key: windows.HKEY = undefined;
|
||||||
|
var access: windows.REGSAM = windows.KEY_QUERY_VALUE | windows.KEY_ENUMERATE_SUB_KEYS;
|
||||||
|
if (options.wow64_32) access |= windows.KEY_WOW64_32KEY;
|
||||||
const return_code_int: windows.HRESULT = windows.advapi32.RegOpenKeyExW(
|
const return_code_int: windows.HRESULT = windows.advapi32.RegOpenKeyExW(
|
||||||
hkey,
|
hkey,
|
||||||
key_wtf16le,
|
key_wtf16le,
|
||||||
0,
|
0,
|
||||||
windows.KEY_QUERY_VALUE | windows.KEY_WOW64_32KEY | windows.KEY_ENUMERATE_SUB_KEYS,
|
access,
|
||||||
&key,
|
&key,
|
||||||
);
|
);
|
||||||
const return_code: windows.Win32Error = @enumFromInt(return_code_int);
|
const return_code: windows.Win32Error = @enumFromInt(return_code_int);
|
||||||
@ -484,13 +492,14 @@ pub const Installation = struct {
|
|||||||
version_key_name: []const u8,
|
version_key_name: []const u8,
|
||||||
) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation {
|
) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation {
|
||||||
var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined;
|
var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined;
|
||||||
const key = key: for ([_][]const u8{ "\\Wow6432Node", "" }) |wow6432node| {
|
const key_name = std.fmt.bufPrint(
|
||||||
for ([_]windows.HKEY{ windows.HKEY_LOCAL_MACHINE, windows.HKEY_CURRENT_USER }) |hkey| {
|
|
||||||
break :key RegistryWtf8.openKey(hkey, std.fmt.bufPrint(
|
|
||||||
&key_name_buf,
|
&key_name_buf,
|
||||||
"SOFTWARE{s}\\Microsoft\\Microsoft SDKs\\Windows\\{s}",
|
"SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\{s}",
|
||||||
.{ wow6432node, version_key_name },
|
.{version_key_name},
|
||||||
) catch unreachable) catch |err| switch (err) {
|
) catch unreachable;
|
||||||
|
const key = key: for ([_]bool{ true, false }) |wow6432node| {
|
||||||
|
for ([_]windows.HKEY{ windows.HKEY_LOCAL_MACHINE, windows.HKEY_CURRENT_USER }) |hkey| {
|
||||||
|
break :key RegistryWtf8.openKey(hkey, key_name, .{ .wow64_32 = wow6432node }) catch |err| switch (err) {
|
||||||
error.KeyNotFound => return error.InstallationNotFound,
|
error.KeyNotFound => return error.InstallationNotFound,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -563,6 +572,7 @@ pub const Installation = struct {
|
|||||||
const options_key = RegistryWtf8.openKey(
|
const options_key = RegistryWtf8.openKey(
|
||||||
windows.HKEY_LOCAL_MACHINE,
|
windows.HKEY_LOCAL_MACHINE,
|
||||||
reg_query_as_wtf8,
|
reg_query_as_wtf8,
|
||||||
|
.{ .wow64_32 = true },
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
error.KeyNotFound => return false,
|
error.KeyNotFound => return false,
|
||||||
};
|
};
|
||||||
@ -587,9 +597,34 @@ pub const Installation = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MsvcLibDir = struct {
|
const MsvcLibDir = struct {
|
||||||
|
fn findInstancesDirViaSetup(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
|
||||||
|
const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup";
|
||||||
|
const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) {
|
||||||
|
error.KeyNotFound => return error.PathNotFound,
|
||||||
|
};
|
||||||
|
defer vs_setup_key.closeKey();
|
||||||
|
|
||||||
|
const packages_path = vs_setup_key.getString(allocator, "", "CachePath") catch |err| switch (err) {
|
||||||
|
error.NotAString,
|
||||||
|
error.ValueNameNotFound,
|
||||||
|
error.StringNotFound,
|
||||||
|
=> return error.PathNotFound,
|
||||||
|
|
||||||
|
error.OutOfMemory => return error.OutOfMemory,
|
||||||
|
};
|
||||||
|
defer allocator.free(packages_path);
|
||||||
|
|
||||||
|
if (!std.fs.path.isAbsolute(packages_path)) return error.PathNotFound;
|
||||||
|
|
||||||
|
const instances_path = try std.fs.path.join(allocator, &.{ packages_path, "_Instances" });
|
||||||
|
defer allocator.free(instances_path);
|
||||||
|
|
||||||
|
return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
fn findInstancesDirViaCLSID(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
|
fn findInstancesDirViaCLSID(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
|
||||||
const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}";
|
const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}";
|
||||||
const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid) catch |err| switch (err) {
|
const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) {
|
||||||
error.KeyNotFound => return error.PathNotFound,
|
error.KeyNotFound => return error.PathNotFound,
|
||||||
};
|
};
|
||||||
defer setup_config_key.closeKey();
|
defer setup_config_key.closeKey();
|
||||||
@ -604,6 +639,8 @@ const MsvcLibDir = struct {
|
|||||||
};
|
};
|
||||||
defer allocator.free(dll_path);
|
defer allocator.free(dll_path);
|
||||||
|
|
||||||
|
if (!std.fs.path.isAbsolute(dll_path)) return error.PathNotFound;
|
||||||
|
|
||||||
var path_it = std.fs.path.componentIterator(dll_path) catch return error.PathNotFound;
|
var path_it = std.fs.path.componentIterator(dll_path) catch return error.PathNotFound;
|
||||||
// the .dll filename
|
// the .dll filename
|
||||||
_ = path_it.last();
|
_ = path_it.last();
|
||||||
@ -622,22 +659,40 @@ const MsvcLibDir = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn findInstancesDir(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
|
fn findInstancesDir(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
|
||||||
// First try to get the path from the .dll that would have been
|
// First, try getting the packages cache path from the registry.
|
||||||
|
// This only seems to exist when the path is different from the default.
|
||||||
|
method1: {
|
||||||
|
return findInstancesDirViaSetup(allocator) catch |err| switch (err) {
|
||||||
|
error.OutOfMemory => |e| return e,
|
||||||
|
error.PathNotFound => break :method1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Otherwise, try to get the path from the .dll that would have been
|
||||||
// loaded via COM for SetupConfiguration.
|
// loaded via COM for SetupConfiguration.
|
||||||
return findInstancesDirViaCLSID(allocator) catch |orig_err| {
|
method2: {
|
||||||
|
return findInstancesDirViaCLSID(allocator) catch |err| switch (err) {
|
||||||
|
error.OutOfMemory => |e| return e,
|
||||||
|
error.PathNotFound => break :method2,
|
||||||
|
};
|
||||||
|
}
|
||||||
// If that can't be found, fall back to manually appending
|
// If that can't be found, fall back to manually appending
|
||||||
// `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA%
|
// `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA%
|
||||||
|
method3: {
|
||||||
const program_data = std.process.getEnvVarOwned(allocator, "PROGRAMDATA") catch |err| switch (err) {
|
const program_data = std.process.getEnvVarOwned(allocator, "PROGRAMDATA") catch |err| switch (err) {
|
||||||
error.OutOfMemory => |e| return e,
|
error.OutOfMemory => |e| return e,
|
||||||
else => return orig_err,
|
error.InvalidWtf8 => unreachable,
|
||||||
|
error.EnvironmentVariableNotFound => break :method3,
|
||||||
};
|
};
|
||||||
defer allocator.free(program_data);
|
defer allocator.free(program_data);
|
||||||
|
|
||||||
|
if (!std.fs.path.isAbsolute(program_data)) break :method3;
|
||||||
|
|
||||||
const instances_path = try std.fs.path.join(allocator, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" });
|
const instances_path = try std.fs.path.join(allocator, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" });
|
||||||
defer allocator.free(instances_path);
|
defer allocator.free(instances_path);
|
||||||
|
|
||||||
return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return orig_err;
|
return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch break :method3;
|
||||||
};
|
}
|
||||||
|
return error.PathNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Intended to be equivalent to `ISetupHelper.ParseVersion`
|
/// Intended to be equivalent to `ISetupHelper.ParseVersion`
|
||||||
@ -896,7 +951,7 @@ const MsvcLibDir = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const vs7_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7") catch return error.PathNotFound;
|
const vs7_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", .{ .wow64_32 = true }) catch return error.PathNotFound;
|
||||||
defer vs7_key.closeKey();
|
defer vs7_key.closeKey();
|
||||||
try_vs7_key: {
|
try_vs7_key: {
|
||||||
const path_maybe_with_trailing_slash = vs7_key.getString(allocator, "", "14.0") catch |err| switch (err) {
|
const path_maybe_with_trailing_slash = vs7_key.getString(allocator, "", "14.0") catch |err| switch (err) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user