diff --git a/src/windows_sdk.zig b/src/windows_sdk.zig index ecd0350483..85c10226bd 100644 --- a/src/windows_sdk.zig +++ b/src/windows_sdk.zig @@ -602,6 +602,16 @@ const MsvcLibDir = struct { } defer _ = setup_config.vtable.unknown.Release(setup_config); + var setup_helper: *ISetupHelper = undefined; + switch (setup_config.vtable.unknown.QueryInterface( + setup_config, + ISetupHelper.IID, + @ptrCast(&setup_helper), + )) { + windows.S_OK => {}, + else => return error.PathNotFound, + } + var all_instances: *IEnumSetupInstances = undefined; switch (setup_config.vtable.setup_configuration.EnumInstances(setup_config, &all_instances)) { windows.S_OK => {}, @@ -610,6 +620,8 @@ const MsvcLibDir = struct { } defer _ = all_instances.vtable.unknown.Release(all_instances); + var latest_version: windows.ULONGLONG = 0; + var latest_version_lib_dir: ?[]const u8 = null; while (true) { var cur: *ISetupInstance = undefined; switch (all_instances.vtable.enum_setup_instances.Next(all_instances, 1, &cur, null)) { @@ -620,6 +632,23 @@ const MsvcLibDir = struct { } defer _ = cur.vtable.unknown.Release(cur); + var installation_version_bstr: windows.BSTR = undefined; + switch (cur.vtable.setup_instance.GetInstallationVersion(cur, &installation_version_bstr)) { + windows.S_OK => {}, + windows.E_OUTOFMEMORY => return error.OutOfMemory, + else => continue, + } + defer SysFreeString(installation_version_bstr); + + var parsed_version: windows.ULONGLONG = undefined; + switch (setup_helper.vtable.setup_helper.ParseVersion(setup_helper, installation_version_bstr, &parsed_version)) { + windows.S_OK => {}, + else => continue, + } + + // We want to end up with the most recent version installed + if (parsed_version <= latest_version) continue; + var installation_path_bstr: windows.BSTR = undefined; switch (cur.vtable.setup_instance.GetInstallationPath(cur, &installation_path_bstr)) { windows.S_OK => {}, @@ -635,9 +664,14 @@ const MsvcLibDir = struct { }; errdefer allocator.free(lib_dir_path); - return lib_dir_path; + if (latest_version_lib_dir) |prev_lib_dir| { + allocator.free(prev_lib_dir); + } + latest_version_lib_dir = lib_dir_path; + latest_version = parsed_version; } - return error.PathNotFound; + + return latest_version_lib_dir orelse error.PathNotFound; } fn libDirFromInstallationPath(allocator: std.mem.Allocator, installation_path_w: []const u16) error{ OutOfMemory, PathNotFound }![]const u8 { @@ -999,6 +1033,27 @@ const ISetupInstance = extern struct { } }; +const ISetupHelper = extern struct { + vtable: *extern struct { + unknown: IUnknown.VTable(ISetupHelper), + setup_helper: VTable(ISetupHelper), + }, + + const IID_Value = windows.GUID.parse("{42b21b78-6192-463e-87bf-d577838f1d5c}"); + pub const IID = &IID_Value; + + pub fn VTable(comptime T: type) type { + return extern struct { + ParseVersion: *const fn ( + self: *T, + pwszVersion: windows.BSTR, // [in] + pullVersion: *windows.ULONGLONG, // [out] + ) callconv(windows.WINAPI) windows.HRESULT, + ParseVersionRange: *anyopaque, + }; + } +}; + const SetupConfiguration = extern struct { const CLSID_Value = windows.GUID.parse("{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"); pub const CLSID = &CLSID_Value;