authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-23 14:49:56-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-11-23 14:49:56-05:00
log464ce8ac67eb0ef15cc535d2b10394343dd44a2c
tree62cb6a5673b467b452e50804b0de2be755a53094
parent6f8c597fff01623668912255c3e37d3a4cb00a98
parent0bc4ee17926356a75539086bcef84173b5229a9b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #18091 from squeek502/no-shell32-no-ole32

Remove Zig's internal depedency on `shell32.dll` and `ole32.dll`

5 files changed, 158 insertions(+), 316 deletions(-)

lib/std/fs/get_app_data_dir.zig+5-20
......@@ -15,27 +15,12 @@ pub const GetAppDataDirError = error{
1515pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
1616 switch (builtin.os.tag) {
1717 .windows => {
18 var dir_path_ptr: [*:0]u16 = undefined;
19 switch (os.windows.shell32.SHGetKnownFolderPath(
20 &os.windows.FOLDERID_LocalAppData,
21 os.windows.KF_FLAG_CREATE,
22 null,
23 &dir_path_ptr,
24 )) {
25 os.windows.S_OK => {
26 defer os.windows.ole32.CoTaskMemFree(dir_path_ptr);
27 const global_dir = unicode.utf16leToUtf8Alloc(allocator, mem.sliceTo(dir_path_ptr, 0)) catch |err| switch (err) {
28 error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
29 error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
30 error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
31 error.OutOfMemory => return error.OutOfMemory,
32 };
33 defer allocator.free(global_dir);
34 return fs.path.join(allocator, &[_][]const u8{ global_dir, appname });
35 },
36 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
18 const local_app_data_dir = std.process.getEnvVarOwned(allocator, "LOCALAPPDATA") catch |err| switch (err) {
19 error.OutOfMemory => |e| return e,
3720 else => return error.AppDataDirUnavailable,
38 }
21 };
22 defer allocator.free(local_app_data_dir);
23 return fs.path.join(allocator, &[_][]const u8{ local_app_data_dir, appname });
3924 },
4025 .macos => {
4126 const home_dir = os.getenv("HOME") orelse {
lib/std/os/windows.zig+2-3
......@@ -21,8 +21,6 @@ test {
2121pub const advapi32 = @import("windows/advapi32.zig");
2222pub const kernel32 = @import("windows/kernel32.zig");
2323pub const ntdll = @import("windows/ntdll.zig");
24pub const ole32 = @import("windows/ole32.zig");
25pub const shell32 = @import("windows/shell32.zig");
2624pub const ws2_32 = @import("windows/ws2_32.zig");
2725pub const crypt32 = @import("windows/crypt32.zig");
2826pub const nls = @import("windows/nls.zig");
......@@ -3527,7 +3525,8 @@ pub const SEC_LARGE_PAGES = 0x80000000;
35273525
35283526pub const HKEY = *opaque {};
35293527
3530pub const HKEY_LOCAL_MACHINE: HKEY = @as(HKEY, @ptrFromInt(0x80000002));
3528pub const HKEY_CLASSES_ROOT: HKEY = @ptrFromInt(0x80000000);
3529pub const HKEY_LOCAL_MACHINE: HKEY = @ptrFromInt(0x80000002);
35313530
35323531/// Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY,
35333532/// KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights.
lib/std/os/windows/ole32.zig deleted-12
......@@ -1,12 +0,0 @@
1const std = @import("../../std.zig");
2const windows = std.os.windows;
3const WINAPI = windows.WINAPI;
4const LPVOID = windows.LPVOID;
5const DWORD = windows.DWORD;
6const HRESULT = windows.HRESULT;
7
8pub extern "ole32" fn CoTaskMemFree(pv: LPVOID) callconv(WINAPI) void;
9pub extern "ole32" fn CoUninitialize() callconv(WINAPI) void;
10pub extern "ole32" fn CoGetCurrentProcess() callconv(WINAPI) DWORD;
11pub extern "ole32" fn CoInitialize(pvReserved: ?LPVOID) callconv(WINAPI) HRESULT;
12pub extern "ole32" fn CoInitializeEx(pvReserved: ?LPVOID, dwCoInit: DWORD) callconv(WINAPI) HRESULT;
lib/std/os/windows/shell32.zig deleted-15
......@@ -1,15 +0,0 @@
1const std = @import("../../std.zig");
2const windows = std.os.windows;
3const WINAPI = windows.WINAPI;
4const KNOWNFOLDERID = windows.KNOWNFOLDERID;
5const DWORD = windows.DWORD;
6const HANDLE = windows.HANDLE;
7const WCHAR = windows.WCHAR;
8const HRESULT = windows.HRESULT;
9
10pub extern "shell32" fn SHGetKnownFolderPath(
11 rfid: *const KNOWNFOLDERID,
12 dwFlags: DWORD,
13 hToken: ?HANDLE,
14 ppszPath: *[*:0]WCHAR,
15) callconv(WINAPI) HRESULT;
src/windows_sdk.zig+151-266
......@@ -88,7 +88,7 @@ const RegistryUtf8 = struct {
8888 key: windows.HKEY,
8989
9090 /// Assert that `key` is valid UTF-8 string
91 pub fn openKey(key: []const u8) error{KeyNotFound}!RegistryUtf8 {
91 pub fn openKey(hkey: windows.HKEY, key: []const u8) error{KeyNotFound}!RegistryUtf8 {
9292 const key_utf16le: [:0]const u16 = key_utf16le: {
9393 var key_utf16le_buf: [RegistryUtf16Le.key_name_max_len]u16 = undefined;
9494 const key_utf16le_len: usize = std.unicode.utf8ToUtf16Le(key_utf16le_buf[0..], key) catch |err| switch (err) {
......@@ -98,7 +98,7 @@ const RegistryUtf8 = struct {
9898 break :key_utf16le key_utf16le_buf[0..key_utf16le_len :0];
9999 };
100100
101 const registry_utf16le = try RegistryUtf16Le.openKey(key_utf16le);
101 const registry_utf16le = try RegistryUtf16Le.openKey(hkey, key_utf16le);
102102 return RegistryUtf8{ .key = registry_utf16le.key };
103103 }
104104
......@@ -191,10 +191,10 @@ const RegistryUtf16Le = struct {
191191 /// Under HKEY_LOCAL_MACHINE with flags:
192192 /// KEY_QUERY_VALUE, KEY_WOW64_32KEY, and KEY_ENUMERATE_SUB_KEYS.
193193 /// After finishing work, call `closeKey`.
194 fn openKey(key_utf16le: [:0]const u16) error{KeyNotFound}!RegistryUtf16Le {
194 fn openKey(hkey: windows.HKEY, key_utf16le: [:0]const u16) error{KeyNotFound}!RegistryUtf16Le {
195195 var key: windows.HKEY = undefined;
196196 const return_code_int: windows.HRESULT = windows.advapi32.RegOpenKeyExW(
197 windows.HKEY_LOCAL_MACHINE,
197 hkey,
198198 key_utf16le,
199199 0,
200200 windows.KEY_QUERY_VALUE | windows.KEY_WOW64_32KEY | windows.KEY_ENUMERATE_SUB_KEYS,
......@@ -352,7 +352,7 @@ pub const Windows10Sdk = struct {
352352 /// Caller owns the result's fields.
353353 /// After finishing work, call `free(allocator)`.
354354 fn find(allocator: std.mem.Allocator) error{ OutOfMemory, Windows10SdkNotFound, PathTooLong, VersionTooLong }!Windows10Sdk {
355 const v10_key = RegistryUtf8.openKey("SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0") catch |err| switch (err) {
355 const v10_key = RegistryUtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0") catch |err| switch (err) {
356356 error.KeyNotFound => return error.Windows10SdkNotFound,
357357 };
358358 defer v10_key.closeKey();
......@@ -417,7 +417,7 @@ pub const Windows10Sdk = struct {
417417 error.NoSpaceLeft => return false,
418418 };
419419
420 const options_key = RegistryUtf8.openKey(reg_query_as_utf8) catch |err| switch (err) {
420 const options_key = RegistryUtf8.openKey(windows.HKEY_LOCAL_MACHINE, reg_query_as_utf8) catch |err| switch (err) {
421421 error.KeyNotFound => return false,
422422 };
423423 defer options_key.closeKey();
......@@ -523,7 +523,7 @@ pub const ZigWindowsSDK = struct {
523523 if (builtin.os.tag != .windows) return error.NotFound;
524524
525525 //note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed
526 const roots_key = RegistryUtf8.openKey(WINDOWS_KIT_REG_KEY) catch |err| switch (err) {
526 const roots_key = RegistryUtf8.openKey(windows.HKEY_LOCAL_MACHINE, WINDOWS_KIT_REG_KEY) catch |err| switch (err) {
527527 error.KeyNotFound => return error.NotFound,
528528 };
529529 defer roots_key.closeKey();
......@@ -581,113 +581,169 @@ pub const ZigWindowsSDK = struct {
581581};
582582
583583const MsvcLibDir = struct {
584 // https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration
585 fn findViaCOM(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }![]const u8 {
586 switch (windows.ole32.CoInitializeEx(null, windows.COINIT.MULTITHREADED)) {
587 windows.S_OK, windows.S_FALSE => {},
588 windows.E_OUTOFMEMORY => return error.OutOfMemory,
589 else => return error.PathNotFound,
590 }
591 // > To close the COM library gracefully on a thread, each successful
592 // > call to CoInitialize or CoInitializeEx, including any call that
593 // > returns S_FALSE, must be balanced by a corresponding call to CoUninitialize.
594 // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex
595 defer windows.ole32.CoUninitialize();
596
597 var setup_config: *ISetupConfiguration = undefined;
598 switch (CoCreateInstance(
599 SetupConfiguration.CLSID,
600 null,
601 CLSCTX.INPROC_SERVER | CLSCTX.INPROC_HANDLER,
602 ISetupConfiguration.IID,
603 @ptrCast(&setup_config),
604 )) {
605 windows.S_OK => {},
606 windows.E_OUTOFMEMORY => return error.OutOfMemory,
607 else => return error.PathNotFound,
608 }
609 defer _ = setup_config.vtable.unknown.Release(setup_config);
610
611 var setup_helper: *ISetupHelper = undefined;
612 switch (setup_config.vtable.unknown.QueryInterface(
613 setup_config,
614 ISetupHelper.IID,
615 @ptrCast(&setup_helper),
616 )) {
617 windows.S_OK => {},
618 else => return error.PathNotFound,
619 }
584 fn findInstancesDirViaCLSID(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
585 const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}";
586 const setup_config_key = RegistryUtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid) catch |err| switch (err) {
587 error.KeyNotFound => return error.PathNotFound,
588 };
589 defer setup_config_key.closeKey();
620590
621 var all_instances: *IEnumSetupInstances = undefined;
622 switch (setup_config.vtable.setup_configuration.EnumInstances(setup_config, &all_instances)) {
623 windows.S_OK => {},
624 windows.E_OUTOFMEMORY => return error.OutOfMemory,
625 else => return error.PathNotFound,
626 }
627 defer _ = all_instances.vtable.unknown.Release(all_instances);
628
629 var latest_version: windows.ULONGLONG = 0;
630 var latest_version_lib_dir: ?[]const u8 = null;
631 while (true) {
632 var cur: *ISetupInstance = undefined;
633 switch (all_instances.vtable.enum_setup_instances.Next(all_instances, 1, &cur, null)) {
634 windows.S_OK => {},
635 windows.S_FALSE => break,
636 windows.E_OUTOFMEMORY => return error.OutOfMemory,
637 else => return error.PathNotFound,
638 }
639 defer _ = cur.vtable.unknown.Release(cur);
591 const dll_path = setup_config_key.getString(allocator, "InprocServer32", "") catch |err| switch (err) {
592 error.NotAString,
593 error.ValueNameNotFound,
594 error.StringNotFound,
595 => return error.PathNotFound,
640596
641 var installation_version_bstr: windows.BSTR = undefined;
642 switch (cur.vtable.setup_instance.GetInstallationVersion(cur, &installation_version_bstr)) {
643 windows.S_OK => {},
644 windows.E_OUTOFMEMORY => return error.OutOfMemory,
645 else => continue,
646 }
647 defer SysFreeString(installation_version_bstr);
597 error.OutOfMemory => return error.OutOfMemory,
598 };
599 defer allocator.free(dll_path);
648600
649 var parsed_version: windows.ULONGLONG = undefined;
650 switch (setup_helper.vtable.setup_helper.ParseVersion(setup_helper, installation_version_bstr, &parsed_version)) {
651 windows.S_OK => {},
652 else => continue,
601 var path_it = std.fs.path.componentIterator(dll_path) catch return error.PathNotFound;
602 // the .dll filename
603 _ = path_it.last();
604 const root_path = while (path_it.previous()) |dir_component| {
605 if (std.ascii.eqlIgnoreCase(dir_component.name, "VisualStudio")) {
606 break dir_component.path;
653607 }
608 } else {
609 return error.PathNotFound;
610 };
611
612 const instances_path = try std.fs.path.join(allocator, &.{ root_path, "Packages", "_Instances" });
613 defer allocator.free(instances_path);
614
615 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound;
616 }
617
618 fn findInstancesDir(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }!std.fs.Dir {
619 // First try to get the path from the .dll that would have been
620 // loaded via COM for SetupConfiguration.
621 return findInstancesDirViaCLSID(allocator) catch |orig_err| {
622 // If that can't be found, fall back to manually appending
623 // `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA%
624 const program_data = std.process.getEnvVarOwned(allocator, "PROGRAMDATA") catch |err| switch (err) {
625 error.OutOfMemory => |e| return e,
626 else => return orig_err,
627 };
628 defer allocator.free(program_data);
629
630 const instances_path = try std.fs.path.join(allocator, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" });
631 defer allocator.free(instances_path);
632
633 return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return orig_err;
634 };
635 }
636
637 /// Intended to be equivalent to `ISetupHelper.ParseVersion`
638 /// Example: 17.4.33205.214 -> 0x0011000481b500d6
639 fn parseVersionQuad(version: []const u8) error{InvalidVersion}!u64 {
640 var it = std.mem.splitScalar(u8, version, '.');
641 const a = it.next() orelse return error.InvalidVersion;
642 const b = it.next() orelse return error.InvalidVersion;
643 const c = it.next() orelse return error.InvalidVersion;
644 const d = it.next() orelse return error.InvalidVersion;
645 if (it.next()) |_| return error.InvalidVersion;
646 var result: u64 = undefined;
647 var result_bytes = std.mem.asBytes(&result);
648
649 std.mem.writeInt(
650 u16,
651 result_bytes[0..2],
652 std.fmt.parseUnsigned(u16, d, 10) catch return error.InvalidVersion,
653 .little,
654 );
655 std.mem.writeInt(
656 u16,
657 result_bytes[2..4],
658 std.fmt.parseUnsigned(u16, c, 10) catch return error.InvalidVersion,
659 .little,
660 );
661 std.mem.writeInt(
662 u16,
663 result_bytes[4..6],
664 std.fmt.parseUnsigned(u16, b, 10) catch return error.InvalidVersion,
665 .little,
666 );
667 std.mem.writeInt(
668 u16,
669 result_bytes[6..8],
670 std.fmt.parseUnsigned(u16, a, 10) catch return error.InvalidVersion,
671 .little,
672 );
673
674 return result;
675 }
676
677 /// Intended to be equivalent to ISetupConfiguration.EnumInstances:
678 /// https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration
679 /// but without the use of COM in order to avoid a dependency on ole32.dll
680 ///
681 /// The logic in this function is intended to match what ISetupConfiguration does
682 /// under-the-hood, as verified using Procmon.
683 fn findViaCOM(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }![]const u8 {
684 // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances`
685 // This will contain directories with names of instance IDs like 80a758ca,
686 // which will contain `state.json` files that have the version and
687 // installation directory.
688 var instances_dir = try findInstancesDir(allocator);
689 defer instances_dir.close();
690
691 var state_subpath_buf: [std.fs.MAX_NAME_BYTES + 32]u8 = undefined;
692 var latest_version_lib_dir = std.ArrayListUnmanaged(u8){};
693 errdefer latest_version_lib_dir.deinit(allocator);
694
695 var latest_version: u64 = 0;
696 var instances_dir_it = instances_dir.iterateAssumeFirstIteration();
697 while (instances_dir_it.next() catch return error.PathNotFound) |entry| {
698 if (entry.kind != .directory) continue;
699
700 var fbs = std.io.fixedBufferStream(&state_subpath_buf);
701 const writer = fbs.writer();
702
703 writer.writeAll(entry.name) catch unreachable;
704 writer.writeByte(std.fs.path.sep) catch unreachable;
705 writer.writeAll("state.json") catch unreachable;
706
707 const json_contents = instances_dir.readFileAlloc(allocator, fbs.getWritten(), std.math.maxInt(usize)) catch continue;
708 defer allocator.free(json_contents);
709
710 var parsed = std.json.parseFromSlice(std.json.Value, allocator, json_contents, .{}) catch continue;
711 defer parsed.deinit();
712
713 if (parsed.value != .object) continue;
714 const catalog_info = parsed.value.object.get("catalogInfo") orelse continue;
715 if (catalog_info != .object) continue;
716 const product_version_value = catalog_info.object.get("buildVersion") orelse continue;
717 if (product_version_value != .string) continue;
718 const product_version_text = product_version_value.string;
719 const parsed_version = parseVersionQuad(product_version_text) catch continue;
654720
655721 // We want to end up with the most recent version installed
656722 if (parsed_version <= latest_version) continue;
657723
658 var installation_path_bstr: windows.BSTR = undefined;
659 switch (cur.vtable.setup_instance.GetInstallationPath(cur, &installation_path_bstr)) {
660 windows.S_OK => {},
661 windows.E_OUTOFMEMORY => return error.OutOfMemory,
662 else => continue,
663 }
664 defer SysFreeString(installation_path_bstr);
724 const installation_path = parsed.value.object.get("installationPath") orelse continue;
725 if (installation_path != .string) continue;
665726
666 const installation_path_w = std.mem.span(installation_path_bstr);
667 const lib_dir_path = libDirFromInstallationPath(allocator, installation_path_w) catch |err| switch (err) {
727 const lib_dir_path = libDirFromInstallationPath(allocator, installation_path.string) catch |err| switch (err) {
668728 error.OutOfMemory => |e| return e,
669729 error.PathNotFound => continue,
670730 };
671 errdefer allocator.free(lib_dir_path);
731 defer allocator.free(lib_dir_path);
672732
673 if (latest_version_lib_dir) |prev_lib_dir| {
674 allocator.free(prev_lib_dir);
675 }
676 latest_version_lib_dir = lib_dir_path;
733 latest_version_lib_dir.clearRetainingCapacity();
734 try latest_version_lib_dir.appendSlice(allocator, lib_dir_path);
677735 latest_version = parsed_version;
678736 }
679737
680 return latest_version_lib_dir orelse error.PathNotFound;
738 if (latest_version_lib_dir.items.len == 0) return error.PathNotFound;
739 return latest_version_lib_dir.toOwnedSlice(allocator);
681740 }
682741
683 fn libDirFromInstallationPath(allocator: std.mem.Allocator, installation_path_w: []const u16) error{ OutOfMemory, PathNotFound }![]const u8 {
684 // Each UTF-16LE code unit may be expanded to 3 UTF-8 bytes.
685 var lib_dir_buf = try std.ArrayList(u8).initCapacity(allocator, installation_path_w.len * 3);
742 fn libDirFromInstallationPath(allocator: std.mem.Allocator, installation_path: []const u8) error{ OutOfMemory, PathNotFound }![]const u8 {
743 var lib_dir_buf = try std.ArrayList(u8).initCapacity(allocator, installation_path.len + 64);
686744 errdefer lib_dir_buf.deinit();
687745
688 lib_dir_buf.items.len = std.unicode.utf16leToUtf8(lib_dir_buf.unusedCapacitySlice(), installation_path_w) catch {
689 return error.PathNotFound;
690 };
746 lib_dir_buf.appendSliceAssumeCapacity(installation_path);
691747
692748 if (!std.fs.path.isSep(lib_dir_buf.getLast())) {
693749 try lib_dir_buf.append('\\');
......@@ -838,7 +894,7 @@ const MsvcLibDir = struct {
838894 }
839895 }
840896
841 const vs7_key = RegistryUtf8.openKey("SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7") catch return error.PathNotFound;
897 const vs7_key = RegistryUtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7") catch return error.PathNotFound;
842898 defer vs7_key.closeKey();
843899 try_vs7_key: {
844900 const path_maybe_with_trailing_slash = vs7_key.getString(allocator, "", "14.0") catch |err| switch (err) {
......@@ -910,174 +966,3 @@ const MsvcLibDir = struct {
910966 return full_path;
911967 }
912968};
913
914const IUnknown = extern struct {
915 vtable: *VTable(IUnknown),
916
917 const IID_Value = windows.GUID.parse("{00000000-0000-0000-c000-000000000046}");
918 pub const IID = &IID_Value;
919
920 pub fn VTable(comptime T: type) type {
921 return extern struct {
922 QueryInterface: *const fn (
923 self: *T,
924 riid: ?*const windows.GUID,
925 ppvObject: ?*?*anyopaque,
926 ) callconv(windows.WINAPI) windows.HRESULT,
927 AddRef: *const fn (
928 self: *T,
929 ) callconv(windows.WINAPI) u32,
930 Release: *const fn (
931 self: *T,
932 ) callconv(windows.WINAPI) u32,
933 };
934 }
935};
936
937const ISetupConfiguration = extern struct {
938 vtable: *extern struct {
939 unknown: IUnknown.VTable(ISetupConfiguration),
940 setup_configuration: VTable(ISetupConfiguration),
941 },
942
943 const IID_Value = windows.GUID.parse("{42843719-db4c-46c2-8e7c-64f1816efd5b}");
944 pub const IID = &IID_Value;
945
946 pub fn VTable(comptime T: type) type {
947 return extern struct {
948 EnumInstances: *const fn (
949 self: *T,
950 ppEnumInstances: **IEnumSetupInstances, // [out]
951 ) callconv(windows.WINAPI) windows.HRESULT,
952 GetInstanceForCurrentProcess: *const fn (
953 self: *T,
954 ppInstance: **ISetupInstance, // [out]
955 ) callconv(windows.WINAPI) windows.HRESULT,
956 GetInstanceForPath: *const fn (
957 self: *T,
958 wzPath: windows.LPCWSTR, // [in]
959 ppInstance: **ISetupInstance, // [out]
960 ) callconv(windows.WINAPI) windows.HRESULT,
961 };
962 }
963};
964
965const IEnumSetupInstances = extern struct {
966 vtable: *extern struct {
967 unknown: IUnknown.VTable(IEnumSetupInstances),
968 enum_setup_instances: VTable(IEnumSetupInstances),
969 },
970
971 const IID_Value = windows.GUID.parse("{6380bcff-41d3-4b2e-8b2e-bf8a6810c848}");
972 pub const IID = &IID_Value;
973
974 pub fn VTable(comptime T: type) type {
975 return extern struct {
976 /// Returns S_OK if the number of elements were fetched,
977 /// S_FALSE if nothing was fetched (at end of enumeration),
978 /// E_INVALIDARG if `celt` is greater than 1 and pceltFetched is NULL,
979 /// or E_OUTOFMEMORY if an ISetupInstance could not be allocated.
980 Next: *const fn (
981 self: *T,
982 /// The number of product instances to retrieve
983 celt: windows.ULONG, // [in]
984 /// A pointer to an array of ISetupInstance
985 rgelt: **ISetupInstance, // [out]
986 /// A pointer to the number of product instances retrieved.
987 /// If `celt` is 1 this paramter may be NULL
988 pceltFetched: ?*windows.ULONG,
989 ) callconv(windows.WINAPI) windows.HRESULT,
990 Skip: *const fn (
991 self: *T,
992 /// The number of product instances to skip
993 celt: windows.ULONG, // [in]
994 ) callconv(windows.WINAPI) windows.HRESULT,
995 Reset: *const fn (
996 self: *T,
997 ) callconv(windows.WINAPI) void,
998 Clone: *const fn (
999 self: *T,
1000 ppenum: **IEnumSetupInstances, // [out]
1001 ) callconv(windows.WINAPI) windows.HRESULT,
1002 };
1003 }
1004};
1005
1006const ISetupInstance = extern struct {
1007 vtable: *extern struct {
1008 unknown: IUnknown.VTable(ISetupInstance),
1009 setup_instance: VTable(ISetupInstance),
1010 },
1011
1012 const IID_Value = windows.GUID.parse("{b41463c3-8866-43b5-bc33-2b0676f7f42e}");
1013 pub const IID = &IID_Value;
1014
1015 pub fn VTable(comptime T: type) type {
1016 return extern struct {
1017 GetInstanceId: *const fn (
1018 self: *T,
1019 pbstrInstanceId: *windows.BSTR, // [out]
1020 ) callconv(windows.WINAPI) windows.HRESULT,
1021 GetInstallDate: *const fn (
1022 self: *T,
1023 pInstallDate: *windows.FILETIME, // [out]
1024 ) callconv(windows.WINAPI) windows.HRESULT,
1025 GetInstallationName: *const fn (
1026 self: *T,
1027 pbstrInstallationName: *windows.BSTR, // [out]
1028 ) callconv(windows.WINAPI) windows.HRESULT,
1029 GetInstallationPath: *const fn (
1030 self: *T,
1031 pbstrInstallationPath: *windows.BSTR, // [out]
1032 ) callconv(windows.WINAPI) windows.HRESULT,
1033 GetInstallationVersion: *const fn (
1034 self: *T,
1035 pbstrInstallationVersion: *windows.BSTR, // [out]
1036 ) callconv(windows.WINAPI) windows.HRESULT,
1037 GetDisplayName: *anyopaque,
1038 GetDescription: *anyopaque,
1039 ResolvePath: *anyopaque,
1040 };
1041 }
1042};
1043
1044const ISetupHelper = extern struct {
1045 vtable: *extern struct {
1046 unknown: IUnknown.VTable(ISetupHelper),
1047 setup_helper: VTable(ISetupHelper),
1048 },
1049
1050 const IID_Value = windows.GUID.parse("{42b21b78-6192-463e-87bf-d577838f1d5c}");
1051 pub const IID = &IID_Value;
1052
1053 pub fn VTable(comptime T: type) type {
1054 return extern struct {
1055 ParseVersion: *const fn (
1056 self: *T,
1057 pwszVersion: windows.BSTR, // [in]
1058 pullVersion: *windows.ULONGLONG, // [out]
1059 ) callconv(windows.WINAPI) windows.HRESULT,
1060 ParseVersionRange: *anyopaque,
1061 };
1062 }
1063};
1064
1065const SetupConfiguration = extern struct {
1066 const CLSID_Value = windows.GUID.parse("{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}");
1067 pub const CLSID = &CLSID_Value;
1068};
1069
1070extern "ole32" fn CoCreateInstance(
1071 rclsid: ?*const windows.GUID, // [in]
1072 pUnkOuter: ?*IUnknown, // [in]
1073 dwClsContext: windows.DWORD, // [in]
1074 riid: ?*const windows.GUID, // [in]
1075 ppv: **anyopaque, // [out]
1076) callconv(windows.WINAPI) windows.HRESULT;
1077
1078extern "oleaut32" fn SysFreeString(bstrString: ?windows.BSTR) callconv(windows.WINAPI) void;
1079
1080const CLSCTX = struct {
1081 const INPROC_SERVER = 0x1;
1082 const INPROC_HANDLER = 0x2;
1083};