| ... | @@ -587,6 +587,31 @@ pub const Installation = struct { | ... | @@ -587,6 +587,31 @@ pub const Installation = struct { |
| 587 | }; | 587 | }; |
| 588 | | 588 | |
| 589 | const MsvcLibDir = struct { | 589 | const MsvcLibDir = struct { |
| | 590 | fn findInstancesDirViaSetup(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir { |
| | 591 | const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup"; |
| | 592 | const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path) catch |err| switch (err) { |
| | 593 | error.KeyNotFound => return error.PathNotFound, |
| | 594 | }; |
| | 595 | defer vs_setup_key.closeKey(); |
| | 596 | |
| | 597 | const packages_path = vs_setup_key.getString(allocator, "", "CachePath") catch |err| switch (err) { |
| | 598 | error.NotAString, |
| | 599 | error.ValueNameNotFound, |
| | 600 | error.StringNotFound, |
| | 601 | => return error.PathNotFound, |
| | 602 | |
| | 603 | error.OutOfMemory => return error.OutOfMemory, |
| | 604 | }; |
| | 605 | defer allocator.free(packages_path); |
| | 606 | |
| | 607 | if (!std.fs.path.isAbsolute(packages_path)) return error.PathNotFound; |
| | 608 | |
| | 609 | const instances_path = try std.fs.path.join(allocator, &.{ packages_path, "_Instances" }); |
| | 610 | defer allocator.free(instances_path); |
| | 611 | |
| | 612 | return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound; |
| | 613 | } |
| | 614 | |
| 590 | fn findInstancesDirViaCLSID(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir { | 615 | fn findInstancesDirViaCLSID(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir { |
| 591 | const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"; | 616 | const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"; |
| 592 | const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid) catch |err| switch (err) { | 617 | const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid) catch |err| switch (err) { |
| ... | @@ -604,6 +629,8 @@ const MsvcLibDir = struct { | ... | @@ -604,6 +629,8 @@ const MsvcLibDir = struct { |
| 604 | }; | 629 | }; |
| 605 | defer allocator.free(dll_path); | 630 | defer allocator.free(dll_path); |
| 606 | | 631 | |
| | 632 | if (!std.fs.path.isAbsolute(dll_path)) return error.PathNotFound; |
| | 633 | |
| 607 | var path_it = std.fs.path.componentIterator(dll_path) catch return error.PathNotFound; | 634 | var path_it = std.fs.path.componentIterator(dll_path) catch return error.PathNotFound; |
| 608 | // the .dll filename | 635 | // the .dll filename |
| 609 | _ = path_it.last(); | 636 | _ = path_it.last(); |
| ... | @@ -622,22 +649,40 @@ const MsvcLibDir = struct { | ... | @@ -622,22 +649,40 @@ const MsvcLibDir = struct { |
| 622 | } | 649 | } |
| 623 | | 650 | |
| 624 | fn findInstancesDir(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir { | 651 | fn findInstancesDir(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir { |
| 625 | // First try to get the path from the .dll that would have been | 652 | // First, try getting the packages cache path from the registry. |
| | 653 | // This only seems to exist when the path is different from the default. |
| | 654 | method1: { |
| | 655 | return findInstancesDirViaSetup(allocator) catch |err| switch (err) { |
| | 656 | error.OutOfMemory => |e| return e, |
| | 657 | error.PathNotFound => break :method1, |
| | 658 | }; |
| | 659 | } |
| | 660 | // Otherwise, try to get the path from the .dll that would have been |
| 626 | // loaded via COM for SetupConfiguration. | 661 | // loaded via COM for SetupConfiguration. |
| 627 | return findInstancesDirViaCLSID(allocator) catch |orig_err| { | 662 | method2: { |
| 628 | // If that can't be found, fall back to manually appending | 663 | return findInstancesDirViaCLSID(allocator) catch |err| switch (err) { |
| 629 | // `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA% | 664 | error.OutOfMemory => |e| return e, |
| | 665 | error.PathNotFound => break :method2, |
| | 666 | }; |
| | 667 | } |
| | 668 | // If that can't be found, fall back to manually appending |
| | 669 | // `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA% |
| | 670 | method3: { |
| 630 | const program_data = std.process.getEnvVarOwned(allocator, "PROGRAMDATA") catch |err| switch (err) { | 671 | const program_data = std.process.getEnvVarOwned(allocator, "PROGRAMDATA") catch |err| switch (err) { |
| 631 | error.OutOfMemory => |e| return e, | 672 | error.OutOfMemory => |e| return e, |
| 632 | else => return orig_err, | 673 | error.InvalidWtf8 => unreachable, |
| | 674 | error.EnvironmentVariableNotFound => break :method3, |
| 633 | }; | 675 | }; |
| 634 | defer allocator.free(program_data); | 676 | defer allocator.free(program_data); |
| 635 | | 677 | |
| | 678 | if (!std.fs.path.isAbsolute(program_data)) break :method3; |
| | 679 | |
| 636 | const instances_path = try std.fs.path.join(allocator, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" }); | 680 | const instances_path = try std.fs.path.join(allocator, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" }); |
| 637 | defer allocator.free(instances_path); | 681 | defer allocator.free(instances_path); |
| 638 | | 682 | |
| 639 | return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return orig_err; | 683 | return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch break :method3; |
| 640 | }; | 684 | } |
| | 685 | return error.PathNotFound; |
| 641 | } | 686 | } |
| 642 | | 687 | |
| 643 | /// Intended to be equivalent to `ISetupHelper.ParseVersion` | 688 | /// Intended to be equivalent to `ISetupHelper.ParseVersion` |