| ... | @@ -602,6 +602,16 @@ const MsvcLibDir = struct { | ... | @@ -602,6 +602,16 @@ const MsvcLibDir = struct { |
| 602 | } | 602 | } |
| 603 | defer _ = setup_config.vtable.unknown.Release(setup_config); | 603 | defer _ = setup_config.vtable.unknown.Release(setup_config); |
| 604 | | 604 | |
| | 605 | var setup_helper: *ISetupHelper = undefined; |
| | 606 | switch (setup_config.vtable.unknown.QueryInterface( |
| | 607 | setup_config, |
| | 608 | ISetupHelper.IID, |
| | 609 | @ptrCast(&setup_helper), |
| | 610 | )) { |
| | 611 | windows.S_OK => {}, |
| | 612 | else => return error.PathNotFound, |
| | 613 | } |
| | 614 | |
| 605 | var all_instances: *IEnumSetupInstances = undefined; | 615 | var all_instances: *IEnumSetupInstances = undefined; |
| 606 | switch (setup_config.vtable.setup_configuration.EnumInstances(setup_config, &all_instances)) { | 616 | switch (setup_config.vtable.setup_configuration.EnumInstances(setup_config, &all_instances)) { |
| 607 | windows.S_OK => {}, | 617 | windows.S_OK => {}, |
| ... | @@ -610,6 +620,8 @@ const MsvcLibDir = struct { | ... | @@ -610,6 +620,8 @@ const MsvcLibDir = struct { |
| 610 | } | 620 | } |
| 611 | defer _ = all_instances.vtable.unknown.Release(all_instances); | 621 | defer _ = all_instances.vtable.unknown.Release(all_instances); |
| 612 | | 622 | |
| | 623 | var latest_version: windows.ULONGLONG = 0; |
| | 624 | var latest_version_lib_dir: ?[]const u8 = null; |
| 613 | while (true) { | 625 | while (true) { |
| 614 | var cur: *ISetupInstance = undefined; | 626 | var cur: *ISetupInstance = undefined; |
| 615 | switch (all_instances.vtable.enum_setup_instances.Next(all_instances, 1, &cur, null)) { | 627 | switch (all_instances.vtable.enum_setup_instances.Next(all_instances, 1, &cur, null)) { |
| ... | @@ -620,6 +632,23 @@ const MsvcLibDir = struct { | ... | @@ -620,6 +632,23 @@ const MsvcLibDir = struct { |
| 620 | } | 632 | } |
| 621 | defer _ = cur.vtable.unknown.Release(cur); | 633 | defer _ = cur.vtable.unknown.Release(cur); |
| 622 | | 634 | |
| | 635 | var installation_version_bstr: windows.BSTR = undefined; |
| | 636 | switch (cur.vtable.setup_instance.GetInstallationVersion(cur, &installation_version_bstr)) { |
| | 637 | windows.S_OK => {}, |
| | 638 | windows.E_OUTOFMEMORY => return error.OutOfMemory, |
| | 639 | else => continue, |
| | 640 | } |
| | 641 | defer SysFreeString(installation_version_bstr); |
| | 642 | |
| | 643 | var parsed_version: windows.ULONGLONG = undefined; |
| | 644 | switch (setup_helper.vtable.setup_helper.ParseVersion(setup_helper, installation_version_bstr, &parsed_version)) { |
| | 645 | windows.S_OK => {}, |
| | 646 | else => continue, |
| | 647 | } |
| | 648 | |
| | 649 | // We want to end up with the most recent version installed |
| | 650 | if (parsed_version <= latest_version) continue; |
| | 651 | |
| 623 | var installation_path_bstr: windows.BSTR = undefined; | 652 | var installation_path_bstr: windows.BSTR = undefined; |
| 624 | switch (cur.vtable.setup_instance.GetInstallationPath(cur, &installation_path_bstr)) { | 653 | switch (cur.vtable.setup_instance.GetInstallationPath(cur, &installation_path_bstr)) { |
| 625 | windows.S_OK => {}, | 654 | windows.S_OK => {}, |
| ... | @@ -635,9 +664,14 @@ const MsvcLibDir = struct { | ... | @@ -635,9 +664,14 @@ const MsvcLibDir = struct { |
| 635 | }; | 664 | }; |
| 636 | errdefer allocator.free(lib_dir_path); | 665 | errdefer allocator.free(lib_dir_path); |
| 637 | | 666 | |
| 638 | return lib_dir_path; | 667 | if (latest_version_lib_dir) |prev_lib_dir| { |
| | 668 | allocator.free(prev_lib_dir); |
| | 669 | } |
| | 670 | latest_version_lib_dir = lib_dir_path; |
| | 671 | latest_version = parsed_version; |
| 639 | } | 672 | } |
| 640 | return error.PathNotFound; | 673 | |
| | 674 | return latest_version_lib_dir orelse error.PathNotFound; |
| 641 | } | 675 | } |
| 642 | | 676 | |
| 643 | fn libDirFromInstallationPath(allocator: std.mem.Allocator, installation_path_w: []const u16) error{ OutOfMemory, PathNotFound }![]const u8 { | 677 | fn libDirFromInstallationPath(allocator: std.mem.Allocator, installation_path_w: []const u16) error{ OutOfMemory, PathNotFound }![]const u8 { |
| ... | @@ -999,6 +1033,27 @@ const ISetupInstance = extern struct { | ... | @@ -999,6 +1033,27 @@ const ISetupInstance = extern struct { |
| 999 | } | 1033 | } |
| 1000 | }; | 1034 | }; |
| 1001 | | 1035 | |
| | 1036 | const ISetupHelper = extern struct { |
| | 1037 | vtable: *extern struct { |
| | 1038 | unknown: IUnknown.VTable(ISetupHelper), |
| | 1039 | setup_helper: VTable(ISetupHelper), |
| | 1040 | }, |
| | 1041 | |
| | 1042 | const IID_Value = windows.GUID.parse("{42b21b78-6192-463e-87bf-d577838f1d5c}"); |
| | 1043 | pub const IID = &IID_Value; |
| | 1044 | |
| | 1045 | pub fn VTable(comptime T: type) type { |
| | 1046 | return extern struct { |
| | 1047 | ParseVersion: *const fn ( |
| | 1048 | self: *T, |
| | 1049 | pwszVersion: windows.BSTR, // [in] |
| | 1050 | pullVersion: *windows.ULONGLONG, // [out] |
| | 1051 | ) callconv(windows.WINAPI) windows.HRESULT, |
| | 1052 | ParseVersionRange: *anyopaque, |
| | 1053 | }; |
| | 1054 | } |
| | 1055 | }; |
| | 1056 | |
| 1002 | const SetupConfiguration = extern struct { | 1057 | const SetupConfiguration = extern struct { |
| 1003 | const CLSID_Value = windows.GUID.parse("{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"); | 1058 | const CLSID_Value = windows.GUID.parse("{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"); |
| 1004 | pub const CLSID = &CLSID_Value; | 1059 | pub const CLSID = &CLSID_Value; |