Commit 41aaf1e6e8

Ryan Liptak <squeek502@hotmail.com>
2023-07-29 08:36:04
windows_sdk: Get the latest installed version when using COM
Before, iteration would stop whenever an installation with vcruntime.lib was found, but that may not be the most recent installed version. Instead, we now iterate all installed instances and choose the one with the newest version.
1 parent 8579f72
Changed files (1)
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;