| ... | ... | @@ -602,6 +602,16 @@ const MsvcLibDir = struct { |
| 602 | 602 | } |
| 603 | 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 | 615 | var all_instances: *IEnumSetupInstances = undefined; |
| 606 | 616 | switch (setup_config.vtable.setup_configuration.EnumInstances(setup_config, &all_instances)) { |
| 607 | 617 | windows.S_OK => {}, |
| ... | ... | @@ -610,6 +620,8 @@ const MsvcLibDir = struct { |
| 610 | 620 | } |
| 611 | 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 | 625 | while (true) { |
| 614 | 626 | var cur: *ISetupInstance = undefined; |
| 615 | 627 | switch (all_instances.vtable.enum_setup_instances.Next(all_instances, 1, &cur, null)) { |
| ... | ... | @@ -620,6 +632,23 @@ const MsvcLibDir = struct { |
| 620 | 632 | } |
| 621 | 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 | 652 | var installation_path_bstr: windows.BSTR = undefined; |
| 624 | 653 | switch (cur.vtable.setup_instance.GetInstallationPath(cur, &installation_path_bstr)) { |
| 625 | 654 | windows.S_OK => {}, |
| ... | ... | @@ -635,9 +664,14 @@ const MsvcLibDir = struct { |
| 635 | 664 | }; |
| 636 | 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 | 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 | 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 | 1057 | const SetupConfiguration = extern struct { |
| 1003 | 1058 | const CLSID_Value = windows.GUID.parse("{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"); |
| 1004 | 1059 | pub const CLSID = &CLSID_Value; |