| author | |
| committer | |
| log | 38d10ee4d0ae6f3ea24a1e5e951127b27e979297 |
| tree | cad969a92afec50b431350fe646907521b76c528 |
| parent | 664ecdfb8e0df58912e8a7b445e8390370b28ccd |
| signature |
Signed-off-by: Eric Joldasov <bratishkaerik@getgoogleoff.me>7 files changed, 782 insertions(+), 1412 deletions(-)
CMakeLists.txt-2| ... | @@ -193,8 +193,6 @@ set(ZIG_CPP_SOURCES | ... | @@ -193,8 +193,6 @@ set(ZIG_CPP_SOURCES |
| 193 | "${CMAKE_SOURCE_DIR}/src/zig_clang_driver.cpp" | 193 | "${CMAKE_SOURCE_DIR}/src/zig_clang_driver.cpp" |
| 194 | "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1_main.cpp" | 194 | "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1_main.cpp" |
| 195 | "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1as_main.cpp" | 195 | "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1as_main.cpp" |
| 196 | # https://github.com/ziglang/zig/issues/6363 | ||
| 197 | "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" | ||
| 198 | ) | 196 | ) |
| 199 | # Needed because we use cmake, not the zig build system, to build zig2.o. | 197 | # Needed because we use cmake, not the zig build system, to build zig2.o. |
| 200 | set(ZIG_STAGE2_SOURCES | 198 | set(ZIG_STAGE2_SOURCES |
build.zig-2| ... | @@ -926,8 +926,6 @@ const zig_cpp_sources = [_][]const u8{ | ... | @@ -926,8 +926,6 @@ const zig_cpp_sources = [_][]const u8{ |
| 926 | "src/zig_clang_driver.cpp", | 926 | "src/zig_clang_driver.cpp", |
| 927 | "src/zig_clang_cc1_main.cpp", | 927 | "src/zig_clang_cc1_main.cpp", |
| 928 | "src/zig_clang_cc1as_main.cpp", | 928 | "src/zig_clang_cc1as_main.cpp", |
| 929 | // https://github.com/ziglang/zig/issues/6363 | ||
| 930 | "src/windows_sdk.cpp", | ||
| 931 | }; | 929 | }; |
| 932 | 930 | ||
| 933 | const clang_libs = [_][]const u8{ | 931 | const clang_libs = [_][]const u8{ |
src/libc_installation.zig+28-35| ... | @@ -186,21 +186,19 @@ pub const LibCInstallation = struct { | ... | @@ -186,21 +186,19 @@ pub const LibCInstallation = struct { |
| 186 | } else if (is_windows) { | 186 | } else if (is_windows) { |
| 187 | if (!build_options.have_llvm) | 187 | if (!build_options.have_llvm) |
| 188 | return error.WindowsSdkNotFound; | 188 | return error.WindowsSdkNotFound; |
| 189 | var sdk: *ZigWindowsSDK = undefined; | 189 | |
| 190 | switch (ZigWindowsSDK.find(&sdk)) { | 190 | var sdk: ZigWindowsSDK = ZigWindowsSDK.find(args.allocator) catch |err| switch (err) { |
| 191 | .None => { | 191 | error.NotFound => return error.WindowsSdkNotFound, |
| 192 | defer sdk.free(); | 192 | error.PathTooLong => return error.WindowsSdkNotFound, |
| 193 | 193 | error.OutOfMemory => return error.OutOfMemory, | |
| 194 | try self.findNativeMsvcIncludeDir(args, sdk); | 194 | }; |
| 195 | try self.findNativeMsvcLibDir(args, sdk); | 195 | defer sdk.free(args.allocator); |
| 196 | try self.findNativeKernel32LibDir(args, sdk); | 196 | |
| 197 | try self.findNativeIncludeDirWindows(args, sdk); | 197 | try self.findNativeMsvcIncludeDir(args, &sdk); |
| 198 | try self.findNativeCrtDirWindows(args, sdk); | 198 | try self.findNativeMsvcLibDir(args, &sdk); |
| 199 | }, | 199 | try self.findNativeKernel32LibDir(args, &sdk); |
| 200 | .OutOfMemory => return error.OutOfMemory, | 200 | try self.findNativeIncludeDirWindows(args, &sdk); |
| 201 | .NotFound => return error.WindowsSdkNotFound, | 201 | try self.findNativeCrtDirWindows(args, &sdk); |
| 202 | .PathTooLong => return error.WindowsSdkNotFound, | ||
| 203 | } | ||
| 204 | } else if (is_haiku) { | 202 | } else if (is_haiku) { |
| 205 | try self.findNativeIncludeDirPosix(args); | 203 | try self.findNativeIncludeDirPosix(args); |
| 206 | try self.findNativeCrtBeginDirHaiku(args); | 204 | try self.findNativeCrtBeginDirHaiku(args); |
| ... | @@ -512,8 +510,7 @@ pub const LibCInstallation = struct { | ... | @@ -512,8 +510,7 @@ pub const LibCInstallation = struct { |
| 512 | ) FindError!void { | 510 | ) FindError!void { |
| 513 | const allocator = args.allocator; | 511 | const allocator = args.allocator; |
| 514 | 512 | ||
| 515 | const msvc_lib_dir_ptr = sdk.msvc_lib_dir_ptr orelse return error.LibCStdLibHeaderNotFound; | 513 | const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCStdLibHeaderNotFound; |
| 516 | const msvc_lib_dir = msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]; | ||
| 517 | const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound; | 514 | const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound; |
| 518 | const up2 = fs.path.dirname(up1) orelse return error.LibCStdLibHeaderNotFound; | 515 | const up2 = fs.path.dirname(up1) orelse return error.LibCStdLibHeaderNotFound; |
| 519 | 516 | ||
| ... | @@ -544,8 +541,8 @@ pub const LibCInstallation = struct { | ... | @@ -544,8 +541,8 @@ pub const LibCInstallation = struct { |
| 544 | sdk: *ZigWindowsSDK, | 541 | sdk: *ZigWindowsSDK, |
| 545 | ) FindError!void { | 542 | ) FindError!void { |
| 546 | const allocator = args.allocator; | 543 | const allocator = args.allocator; |
| 547 | const msvc_lib_dir_ptr = sdk.msvc_lib_dir_ptr orelse return error.LibCRuntimeNotFound; | 544 | const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCRuntimeNotFound; |
| 548 | self.msvc_lib_dir = try allocator.dupeZ(u8, msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]); | 545 | self.msvc_lib_dir = try allocator.dupe(u8, msvc_lib_dir); |
| 549 | } | 546 | } |
| 550 | }; | 547 | }; |
| 551 | 548 | ||
| ... | @@ -657,23 +654,19 @@ const Search = struct { | ... | @@ -657,23 +654,19 @@ const Search = struct { |
| 657 | 654 | ||
| 658 | fn fillSearch(search_buf: *[2]Search, sdk: *ZigWindowsSDK) []Search { | 655 | fn fillSearch(search_buf: *[2]Search, sdk: *ZigWindowsSDK) []Search { |
| 659 | var search_end: usize = 0; | 656 | var search_end: usize = 0; |
| 660 | if (sdk.path10_ptr) |path10_ptr| { | 657 | if (sdk.windows10sdk) |windows10sdk| { |
| 661 | if (sdk.version10_ptr) |version10_ptr| { | 658 | search_buf[search_end] = .{ |
| 662 | search_buf[search_end] = Search{ | 659 | .path = windows10sdk.path, |
| 663 | .path = path10_ptr[0..sdk.path10_len], | 660 | .version = windows10sdk.version, |
| 664 | .version = version10_ptr[0..sdk.version10_len], | 661 | }; |
| 665 | }; | 662 | search_end += 1; |
| 666 | search_end += 1; | ||
| 667 | } | ||
| 668 | } | 663 | } |
| 669 | if (sdk.path81_ptr) |path81_ptr| { | 664 | if (sdk.windows81sdk) |windows81sdk| { |
| 670 | if (sdk.version81_ptr) |version81_ptr| { | 665 | search_buf[search_end] = .{ |
| 671 | search_buf[search_end] = Search{ | 666 | .path = windows81sdk.path, |
| 672 | .path = path81_ptr[0..sdk.path81_len], | 667 | .version = windows81sdk.version, |
| 673 | .version = version81_ptr[0..sdk.version81_len], | 668 | }; |
| 674 | }; | 669 | search_end += 1; |
| 675 | search_end += 1; | ||
| 676 | } | ||
| 677 | } | 670 | } |
| 678 | return search_buf[0..search_end]; | 671 | return search_buf[0..search_end]; |
| 679 | } | 672 | } |
src/windows_com.hpp deleted-909| ... | @@ -1,909 +0,0 @@ | ||
| 1 | // The MIT License(MIT) | ||
| 2 | // Copyright(C) Microsoft Corporation.All rights reserved. | ||
| 3 | // | ||
| 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 5 | // of this software and associated documentation files(the "Software"), to deal | ||
| 6 | // in the Software without restriction, including without limitation the rights | ||
| 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell | ||
| 8 | // copies of the Software, and to permit persons to whom the Software is | ||
| 9 | // furnished to do so, subject to the following conditions : | ||
| 10 | // | ||
| 11 | // The above copyright notice and this permission notice shall be included in | ||
| 12 | // all copies or substantial portions of the Software. | ||
| 13 | // | ||
| 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE | ||
| 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 20 | // IN THE SOFTWARE. | ||
| 21 | // | ||
| 22 | |||
| 23 | #pragma once | ||
| 24 | |||
| 25 | // Windows headers | ||
| 26 | #include <windows.h> | ||
| 27 | #include <fcntl.h> | ||
| 28 | #include <io.h> | ||
| 29 | #include <shellapi.h> | ||
| 30 | |||
| 31 | // Standard headers | ||
| 32 | #include <stdio.h> | ||
| 33 | |||
| 34 | // COM support header files | ||
| 35 | #include <comdef.h> | ||
| 36 | |||
| 37 | // Constants | ||
| 38 | // | ||
| 39 | #ifndef E_NOTFOUND | ||
| 40 | #define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #ifndef E_FILENOTFOUND | ||
| 44 | #define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #ifndef E_NOTSUPPORTED | ||
| 48 | #define E_NOTSUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) | ||
| 49 | #endif | ||
| 50 | |||
| 51 | // Enumerations | ||
| 52 | // | ||
| 53 | /// <summary> | ||
| 54 | /// The state of an instance. | ||
| 55 | /// </summary> | ||
| 56 | enum InstanceState | ||
| 57 | { | ||
| 58 | 	/// <summary> | ||
| 59 | 	/// The instance state has not been determined. | ||
| 60 | 	/// </summary> | ||
| 61 | 	eNone = 0, | ||
| 62 | |||
| 63 | 	/// <summary> | ||
| 64 | 	/// The instance installation path exists. | ||
| 65 | 	/// </summary> | ||
| 66 | 	eLocal = 1, | ||
| 67 | |||
| 68 | 	/// <summary> | ||
| 69 | 	/// A product is registered to the instance. | ||
| 70 | 	/// </summary> | ||
| 71 | 	eRegistered = 2, | ||
| 72 | |||
| 73 | 	/// <summary> | ||
| 74 | 	/// No reboot is required for the instance. | ||
| 75 | 	/// </summary> | ||
| 76 | 	eNoRebootRequired = 4, | ||
| 77 | |||
| 78 | 	/// <summary> | ||
| 79 | 	/// No errors were reported for the instance. | ||
| 80 | 	/// </summary> | ||
| 81 | 	eNoErrors = 8, | ||
| 82 | |||
| 83 | 	/// <summary> | ||
| 84 | 	/// The instance represents a complete install. | ||
| 85 | 	/// </summary> | ||
| 86 | 	eComplete = UINT_MAX, | ||
| 87 | }; | ||
| 88 | |||
| 89 | // Forward interface declarations | ||
| 90 | // | ||
| 91 | #ifndef __ISetupInstance_FWD_DEFINED__ | ||
| 92 | #define __ISetupInstance_FWD_DEFINED__ | ||
| 93 | typedef struct ISetupInstance ISetupInstance; | ||
| 94 | #endif | ||
| 95 | |||
| 96 | #ifndef __ISetupInstance2_FWD_DEFINED__ | ||
| 97 | #define __ISetupInstance2_FWD_DEFINED__ | ||
| 98 | typedef struct ISetupInstance2 ISetupInstance2; | ||
| 99 | #endif | ||
| 100 | |||
| 101 | #ifndef __ISetupInstanceCatalog_FWD_DEFINED__ | ||
| 102 | #define __ISetupInstanceCatalog_FWD_DEFINED__ | ||
| 103 | typedef struct ISetupInstanceCatalog ISetupInstanceCatalog; | ||
| 104 | #endif | ||
| 105 | |||
| 106 | #ifndef __ISetupLocalizedProperties_FWD_DEFINED__ | ||
| 107 | #define __ISetupLocalizedProperties_FWD_DEFINED__ | ||
| 108 | typedef struct ISetupLocalizedProperties ISetupLocalizedProperties; | ||
| 109 | #endif | ||
| 110 | |||
| 111 | #ifndef __IEnumSetupInstances_FWD_DEFINED__ | ||
| 112 | #define __IEnumSetupInstances_FWD_DEFINED__ | ||
| 113 | typedef struct IEnumSetupInstances IEnumSetupInstances; | ||
| 114 | #endif | ||
| 115 | |||
| 116 | #ifndef __ISetupConfiguration_FWD_DEFINED__ | ||
| 117 | #define __ISetupConfiguration_FWD_DEFINED__ | ||
| 118 | typedef struct ISetupConfiguration ISetupConfiguration; | ||
| 119 | #endif | ||
| 120 | |||
| 121 | #ifndef __ISetupConfiguration2_FWD_DEFINED__ | ||
| 122 | #define __ISetupConfiguration2_FWD_DEFINED__ | ||
| 123 | typedef struct ISetupConfiguration2 ISetupConfiguration2; | ||
| 124 | #endif | ||
| 125 | |||
| 126 | #ifndef __ISetupPackageReference_FWD_DEFINED__ | ||
| 127 | #define __ISetupPackageReference_FWD_DEFINED__ | ||
| 128 | typedef struct ISetupPackageReference ISetupPackageReference; | ||
| 129 | #endif | ||
| 130 | |||
| 131 | #ifndef __ISetupHelper_FWD_DEFINED__ | ||
| 132 | #define __ISetupHelper_FWD_DEFINED__ | ||
| 133 | typedef struct ISetupHelper ISetupHelper; | ||
| 134 | #endif | ||
| 135 | |||
| 136 | #ifndef __ISetupErrorState_FWD_DEFINED__ | ||
| 137 | #define __ISetupErrorState_FWD_DEFINED__ | ||
| 138 | typedef struct ISetupErrorState ISetupErrorState; | ||
| 139 | #endif | ||
| 140 | |||
| 141 | #ifndef __ISetupErrorState2_FWD_DEFINED__ | ||
| 142 | #define __ISetupErrorState2_FWD_DEFINED__ | ||
| 143 | typedef struct ISetupErrorState2 ISetupErrorState2; | ||
| 144 | #endif | ||
| 145 | |||
| 146 | #ifndef __ISetupFailedPackageReference_FWD_DEFINED__ | ||
| 147 | #define __ISetupFailedPackageReference_FWD_DEFINED__ | ||
| 148 | typedef struct ISetupFailedPackageReference ISetupFailedPackageReference; | ||
| 149 | #endif | ||
| 150 | |||
| 151 | #ifndef __ISetupFailedPackageReference2_FWD_DEFINED__ | ||
| 152 | #define __ISetupFailedPackageReference2_FWD_DEFINED__ | ||
| 153 | typedef struct ISetupFailedPackageReference2 ISetupFailedPackageReference2; | ||
| 154 | #endif | ||
| 155 | |||
| 156 | #ifndef __ISetupPropertyStore_FWD_DEFINED__ | ||
| 157 | #define __ISetupPropertyStore_FWD_DEFINED__ | ||
| 158 | typedef struct ISetupPropertyStore ISetupPropertyStore; | ||
| 159 | #endif | ||
| 160 | |||
| 161 | #ifndef __ISetupLocalizedPropertyStore_FWD_DEFINED__ | ||
| 162 | #define __ISetupLocalizedPropertyStore_FWD_DEFINED__ | ||
| 163 | typedef struct ISetupLocalizedPropertyStore ISetupLocalizedPropertyStore; | ||
| 164 | #endif | ||
| 165 | |||
| 166 | // Forward class declarations | ||
| 167 | // | ||
| 168 | #ifndef __SetupConfiguration_FWD_DEFINED__ | ||
| 169 | #define __SetupConfiguration_FWD_DEFINED__ | ||
| 170 | |||
| 171 | #ifdef __cplusplus | ||
| 172 | typedef class SetupConfiguration SetupConfiguration; | ||
| 173 | #endif | ||
| 174 | |||
| 175 | #endif | ||
| 176 | |||
| 177 | #ifndef _MSC_VER | ||
| 178 | #define _Deref_out_opt_ | ||
| 179 | #endif | ||
| 180 | |||
| 181 | #ifdef __cplusplus | ||
| 182 | extern "C" { | ||
| 183 | #endif | ||
| 184 | |||
| 185 | 	// Interface definitions | ||
| 186 | 	// | ||
| 187 | 	EXTERN_C const IID IID_ISetupInstance; | ||
| 188 | |||
| 189 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 190 | 	/// <summary> | ||
| 191 | 	/// Information about an instance of a product. | ||
| 192 | 	/// </summary> | ||
| 193 | 	struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") DECLSPEC_NOVTABLE ISetupInstance : public IUnknown | ||
| 194 | 	{ | ||
| 195 | 		/// <summary> | ||
| 196 | 		/// Gets the instance identifier (should match the name of the parent instance directory). | ||
| 197 | 		/// </summary> | ||
| 198 | 		/// <param name="pbstrInstanceId">The instance identifier.</param> | ||
| 199 | 		/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns> | ||
| 200 | 		STDMETHOD(GetInstanceId)( | ||
| 201 | 			_Out_ BSTR* pbstrInstanceId | ||
| 202 | 			) = 0; | ||
| 203 | |||
| 204 | 	/// <summary> | ||
| 205 | 	/// Gets the local date and time when the installation was originally installed. | ||
| 206 | 	/// </summary> | ||
| 207 | 	/// <param name="pInstallDate">The local date and time when the installation was originally installed.</param> | ||
| 208 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 209 | 	STDMETHOD(GetInstallDate)( | ||
| 210 | 		_Out_ LPFILETIME pInstallDate | ||
| 211 | 		) = 0; | ||
| 212 | |||
| 213 | 	/// <summary> | ||
| 214 | 	/// Gets the unique name of the installation, often indicating the branch and other information used for telemetry. | ||
| 215 | 	/// </summary> | ||
| 216 | 	/// <param name="pbstrInstallationName">The unique name of the installation, often indicating the branch and other information used for telemetry.</param> | ||
| 217 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 218 | 	STDMETHOD(GetInstallationName)( | ||
| 219 | 		_Out_ BSTR* pbstrInstallationName | ||
| 220 | 		) = 0; | ||
| 221 | |||
| 222 | 	/// <summary> | ||
| 223 | 	/// Gets the path to the installation root of the product. | ||
| 224 | 	/// </summary> | ||
| 225 | 	/// <param name="pbstrInstallationPath">The path to the installation root of the product.</param> | ||
| 226 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 227 | 	STDMETHOD(GetInstallationPath)( | ||
| 228 | 		_Out_ BSTR* pbstrInstallationPath | ||
| 229 | 		) = 0; | ||
| 230 | |||
| 231 | 	/// <summary> | ||
| 232 | 	/// Gets the version of the product installed in this instance. | ||
| 233 | 	/// </summary> | ||
| 234 | 	/// <param name="pbstrInstallationVersion">The version of the product installed in this instance.</param> | ||
| 235 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 236 | 	STDMETHOD(GetInstallationVersion)( | ||
| 237 | 		_Out_ BSTR* pbstrInstallationVersion | ||
| 238 | 		) = 0; | ||
| 239 | |||
| 240 | 	/// <summary> | ||
| 241 | 	/// Gets the display name (title) of the product installed in this instance. | ||
| 242 | 	/// </summary> | ||
| 243 | 	/// <param name="lcid">The LCID for the display name.</param> | ||
| 244 | 	/// <param name="pbstrDisplayName">The display name (title) of the product installed in this instance.</param> | ||
| 245 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 246 | 	STDMETHOD(GetDisplayName)( | ||
| 247 | 		_In_ LCID lcid, | ||
| 248 | 		_Out_ BSTR* pbstrDisplayName | ||
| 249 | 		) = 0; | ||
| 250 | |||
| 251 | 	/// <summary> | ||
| 252 | 	/// Gets the description of the product installed in this instance. | ||
| 253 | 	/// </summary> | ||
| 254 | 	/// <param name="lcid">The LCID for the description.</param> | ||
| 255 | 	/// <param name="pbstrDescription">The description of the product installed in this instance.</param> | ||
| 256 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 257 | 	STDMETHOD(GetDescription)( | ||
| 258 | 		_In_ LCID lcid, | ||
| 259 | 		_Out_ BSTR* pbstrDescription | ||
| 260 | 		) = 0; | ||
| 261 | |||
| 262 | 	/// <summary> | ||
| 263 | 	/// Resolves the optional relative path to the root path of the instance. | ||
| 264 | 	/// </summary> | ||
| 265 | 	/// <param name="pwszRelativePath">A relative path within the instance to resolve, or NULL to get the root path.</param> | ||
| 266 | 	/// <param name="pbstrAbsolutePath">The full path to the optional relative path within the instance. If the relative path is NULL, the root path will always terminate in a backslash.</param> | ||
| 267 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns> | ||
| 268 | 	STDMETHOD(ResolvePath)( | ||
| 269 | 		_In_opt_z_ LPCOLESTR pwszRelativePath, | ||
| 270 | 		_Out_ BSTR* pbstrAbsolutePath | ||
| 271 | 		) = 0; | ||
| 272 | 	}; | ||
| 273 | #endif | ||
| 274 | |||
| 275 | 	EXTERN_C const IID IID_ISetupInstance2; | ||
| 276 | |||
| 277 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 278 | 	/// <summary> | ||
| 279 | 	/// Information about an instance of a product. | ||
| 280 | 	/// </summary> | ||
| 281 | 	struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance | ||
| 282 | 	{ | ||
| 283 | 		/// <summary> | ||
| 284 | 		/// Gets the state of the instance. | ||
| 285 | 		/// </summary> | ||
| 286 | 		/// <param name="pState">The state of the instance.</param> | ||
| 287 | 		/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns> | ||
| 288 | 		STDMETHOD(GetState)( | ||
| 289 | 			_Out_ InstanceState* pState | ||
| 290 | 			) = 0; | ||
| 291 | |||
| 292 | 	/// <summary> | ||
| 293 | 	/// Gets an array of package references registered to the instance. | ||
| 294 | 	/// </summary> | ||
| 295 | 	/// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/>.</param> | ||
| 296 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns> | ||
| 297 | 	STDMETHOD(GetPackages)( | ||
| 298 | 		_Out_ LPSAFEARRAY* ppsaPackages | ||
| 299 | 		) = 0; | ||
| 300 | |||
| 301 | 	/// <summary> | ||
| 302 | 	/// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents the registered product. | ||
| 303 | 	/// </summary> | ||
| 304 | 	/// <param name="ppPackage">Pointer to an instance of <see cref="ISetupPackageReference"/>. This may be NULL if <see cref="GetState"/> does not return <see cref="eComplete"/>.</param> | ||
| 305 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns> | ||
| 306 | 	STDMETHOD(GetProduct)( | ||
| 307 | 		_Outptr_result_maybenull_ ISetupPackageReference** ppPackage | ||
| 308 | 		) = 0; | ||
| 309 | |||
| 310 | 	/// <summary> | ||
| 311 | 	/// Gets the relative path to the product application, if available. | ||
| 312 | 	/// </summary> | ||
| 313 | 	/// <param name="pbstrProductPath">The relative path to the product application, if available.</param> | ||
| 314 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns> | ||
| 315 | 	STDMETHOD(GetProductPath)( | ||
| 316 | 		_Outptr_result_maybenull_ BSTR* pbstrProductPath | ||
| 317 | 		) = 0; | ||
| 318 | |||
| 319 | 	/// <summary> | ||
| 320 | 	/// Gets the error state of the instance, if available. | ||
| 321 | 	/// </summary> | ||
| 322 | 	/// <param name="pErrorState">The error state of the instance, if available.</param> | ||
| 323 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns> | ||
| 324 | 	STDMETHOD(GetErrors)( | ||
| 325 | 		_Outptr_result_maybenull_ ISetupErrorState** ppErrorState | ||
| 326 | 		) = 0; | ||
| 327 | |||
| 328 | 	/// <summary> | ||
| 329 | 	/// Gets a value indicating whether the instance can be launched. | ||
| 330 | 	/// </summary> | ||
| 331 | 	/// <param name="pfIsLaunchable">Whether the instance can be launched.</param> | ||
| 332 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 333 | 	/// <remarks> | ||
| 334 | 	/// An instance could have had errors during install but still be launched. Some features may not work correctly, but others will. | ||
| 335 | 	/// </remarks> | ||
| 336 | 	STDMETHOD(IsLaunchable)( | ||
| 337 | 		_Out_ VARIANT_BOOL* pfIsLaunchable | ||
| 338 | 		) = 0; | ||
| 339 | |||
| 340 | 	/// <summary> | ||
| 341 | 	/// Gets a value indicating whether the instance is complete. | ||
| 342 | 	/// </summary> | ||
| 343 | 	/// <param name="pfIsLaunchable">Whether the instance is complete.</param> | ||
| 344 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 345 | 	/// <remarks> | ||
| 346 | 	/// An instance is complete if it had no errors during install, resume, or repair. | ||
| 347 | 	/// </remarks> | ||
| 348 | 	STDMETHOD(IsComplete)( | ||
| 349 | 		_Out_ VARIANT_BOOL* pfIsComplete | ||
| 350 | 		) = 0; | ||
| 351 | |||
| 352 | 	/// <summary> | ||
| 353 | 	/// Gets product-specific properties. | ||
| 354 | 	/// </summary> | ||
| 355 | 	/// <param name="ppProperties">A pointer to an instance of <see cref="ISetupPropertyStore"/>. This may be NULL if no properties are defined.</param> | ||
| 356 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns> | ||
| 357 | 	STDMETHOD(GetProperties)( | ||
| 358 | 		_Outptr_result_maybenull_ ISetupPropertyStore** ppProperties | ||
| 359 | 		) = 0; | ||
| 360 | |||
| 361 | 	/// <summary> | ||
| 362 | 	/// Gets the directory path to the setup engine that installed the instance. | ||
| 363 | 	/// </summary> | ||
| 364 | 	/// <param name="pbstrEnginePath">The directory path to the setup engine that installed the instance.</param> | ||
| 365 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns> | ||
| 366 | 	STDMETHOD(GetEnginePath)( | ||
| 367 | 		_Outptr_result_maybenull_ BSTR* pbstrEnginePath | ||
| 368 | 		) = 0; | ||
| 369 | 	}; | ||
| 370 | #endif | ||
| 371 | |||
| 372 | 	EXTERN_C const IID IID_ISetupInstanceCatalog; | ||
| 373 | |||
| 374 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 375 | 	/// <summary> | ||
| 376 | 	/// Information about a catalog used to install an instance. | ||
| 377 | 	/// </summary> | ||
| 378 | 	struct DECLSPEC_UUID("9AD8E40F-39A2-40F1-BF64-0A6C50DD9EEB") DECLSPEC_NOVTABLE ISetupInstanceCatalog : public IUnknown | ||
| 379 | 	{ | ||
| 380 | 		/// <summary> | ||
| 381 | 		/// Gets catalog information properties. | ||
| 382 | 		/// </summary> | ||
| 383 | 		/// <param name="ppCatalogInfo">A pointer to an instance of <see cref="ISetupPropertyStore"/>.</param> | ||
| 384 | 		/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property does not exist.</returns> | ||
| 385 | 		STDMETHOD(GetCatalogInfo)( | ||
| 386 | 			_Out_ ISetupPropertyStore** ppCatalogInfo | ||
| 387 | 			) = 0; | ||
| 388 | |||
| 389 | 	/// <summary> | ||
| 390 | 	/// Gets a value indicating whether the catalog is a prerelease. | ||
| 391 | 	/// </summary> | ||
| 392 | 	/// <param name="pfIsPrerelease">Whether the catalog for the instance is a prerelease version.</param> | ||
| 393 | 	/// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property does not exist.</returns> | ||
| 394 | 	STDMETHOD(IsPrerelease)( | ||
| 395 | 		_Out_ VARIANT_BOOL* pfIsPrerelease | ||
| 396 | 		) = 0; | ||
| 397 | 	}; | ||
| 398 | #endif | ||
| 399 | |||
| 400 | 	EXTERN_C const IID IID_ISetupLocalizedProperties; | ||
| 401 | |||
| 402 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 403 | 	/// <summary> | ||
| 404 | 	/// Provides localized properties of an instance of a product. | ||
| 405 | 	/// </summary> | ||
| 406 | 	struct DECLSPEC_UUID("F4BD7382-FE27-4AB4-B974-9905B2A148B0") DECLSPEC_NOVTABLE ISetupLocalizedProperties : public IUnknown | ||
| 407 | 	{ | ||
| 408 | 		/// <summary> | ||
| 409 | 		/// Gets localized product-specific properties. | ||
| 410 | 		/// </summary> | ||
| 411 | 		/// <param name="ppLocalizedProperties">A pointer to an instance of <see cref="ISetupLocalizedPropertyStore"/>. This may be NULL if no properties are defined.</param> | ||
| 412 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 413 | 		STDMETHOD(GetLocalizedProperties)( | ||
| 414 | 			_Outptr_result_maybenull_ ISetupLocalizedPropertyStore** ppLocalizedProperties | ||
| 415 | 			) = 0; | ||
| 416 | |||
| 417 | 	/// <summary> | ||
| 418 | 	/// Gets localized channel-specific properties. | ||
| 419 | 	/// </summary> | ||
| 420 | 	/// <param name="ppLocalizedChannelProperties">A pointer to an instance of <see cref="ISetupLocalizedPropertyStore"/>. This may be NULL if no channel properties are defined.</param> | ||
| 421 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 422 | 	STDMETHOD(GetLocalizedChannelProperties)( | ||
| 423 | 		_Outptr_result_maybenull_ ISetupLocalizedPropertyStore** ppLocalizedChannelProperties | ||
| 424 | 		) = 0; | ||
| 425 | 	}; | ||
| 426 | #endif | ||
| 427 | |||
| 428 | 	EXTERN_C const IID IID_IEnumSetupInstances; | ||
| 429 | |||
| 430 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 431 | |||
| 432 | #ifdef __GNUC__ | ||
| 433 | __CRT_UUID_DECL(IEnumSetupInstances, 0x6380BCFF, 0x41D3, 0x4B2E, 0x8B, 0x2E, 0xBF, 0x8A, 0x68, 0x10, 0xC8, 0x48); | ||
| 434 | #endif | ||
| 435 | |||
| 436 | 	/// <summary> | ||
| 437 | 	/// An enumerator of installed <see cref="ISetupInstance"/> objects. | ||
| 438 | 	/// </summary> | ||
| 439 | 	struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown | ||
| 440 | 	{ | ||
| 441 | 		/// <summary> | ||
| 442 | 		/// Retrieves the next set of product instances in the enumeration sequence. | ||
| 443 | 		/// </summary> | ||
| 444 | 		/// <param name="celt">The number of product instances to retrieve.</param> | ||
| 445 | 		/// <param name="rgelt">A pointer to an array of <see cref="ISetupInstance"/>.</param> | ||
| 446 | 		/// <param name="pceltFetched">A pointer to the number of product instances retrieved. If <paramref name="celt"/> is 1 this parameter may be NULL.</param> | ||
| 447 | 		/// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing was fetched (at end of enumeration), E_INVALIDARG if <paramref name="celt"/> is greater than 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see cref="ISetupInstance"/> could not be allocated.</returns> | ||
| 448 | 		STDMETHOD(Next)( | ||
| 449 | 			_In_ ULONG celt, | ||
| 450 | 			_Out_writes_to_(celt, *pceltFetched) ISetupInstance** rgelt, | ||
| 451 | 			_Out_opt_ _Deref_out_range_(0, celt) ULONG* pceltFetched | ||
| 452 | 			) = 0; | ||
| 453 | |||
| 454 | 	/// <summary> | ||
| 455 | 	/// Skips the next set of product instances in the enumeration sequence. | ||
| 456 | 	/// </summary> | ||
| 457 | 	/// <param name="celt">The number of product instances to skip.</param> | ||
| 458 | 	/// <returns>S_OK if the number of elements could be skipped; otherwise, S_FALSE;</returns> | ||
| 459 | 	STDMETHOD(Skip)( | ||
| 460 | 		_In_ ULONG celt | ||
| 461 | 		) = 0; | ||
| 462 | |||
| 463 | 	/// <summary> | ||
| 464 | 	/// Resets the enumeration sequence to the beginning. | ||
| 465 | 	/// </summary> | ||
| 466 | 	/// <returns>Always returns S_OK;</returns> | ||
| 467 | 	STDMETHOD(Reset)(void) = 0; | ||
| 468 | |||
| 469 | 	/// <summary> | ||
| 470 | 	/// Creates a new enumeration object in the same state as the current enumeration object: the new object points to the same place in the enumeration sequence. | ||
| 471 | 	/// </summary> | ||
| 472 | 	/// <param name="ppenum">A pointer to a pointer to a new <see cref="IEnumSetupInstances"/> interface. If the method fails, this parameter is undefined.</param> | ||
| 473 | 	/// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns> | ||
| 474 | 	STDMETHOD(Clone)( | ||
| 475 | 		_Deref_out_opt_ IEnumSetupInstances** ppenum | ||
| 476 | 		) = 0; | ||
| 477 | 	}; | ||
| 478 | #endif | ||
| 479 | |||
| 480 | 	EXTERN_C const IID IID_ISetupConfiguration; | ||
| 481 | |||
| 482 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 483 | |||
| 484 | #ifdef __GNUC__ | ||
| 485 | __CRT_UUID_DECL(ISetupConfiguration, 0x42843719, 0xDB4C, 0x46C2, 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B); | ||
| 486 | #endif | ||
| 487 | |||
| 488 | 	/// <summary> | ||
| 489 | 	/// Gets information about product instances installed on the machine. | ||
| 490 | 	/// </summary> | ||
| 491 | 	struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown | ||
| 492 | 	{ | ||
| 493 | 		/// <summary> | ||
| 494 | 		/// Enumerates all launchable product instances installed. | ||
| 495 | 		/// </summary> | ||
| 496 | 		/// <param name="ppEnumInstances">An enumeration of completed, installed product instances.</param> | ||
| 497 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 498 | 		STDMETHOD(EnumInstances)( | ||
| 499 | 			_Out_ IEnumSetupInstances** ppEnumInstances | ||
| 500 | 			) = 0; | ||
| 501 | |||
| 502 | 	/// <summary> | ||
| 503 | 	/// Gets the instance for the current process path. | ||
| 504 | 	/// </summary> | ||
| 505 | 	/// <param name="ppInstance">The instance for the current process path.</param> | ||
| 506 | 	/// <returns> | ||
| 507 | 	/// The instance for the current process path, or E_NOTFOUND if not found. | ||
| 508 | 	/// The <see cref="ISetupInstance::GetState"/> may indicate the instance is invalid. | ||
| 509 | 	/// </returns> | ||
| 510 | 	/// <remarks> | ||
| 511 | 	/// The returned instance may not be launchable. | ||
| 512 | 	/// </remarks> | ||
| 513 | 	STDMETHOD(GetInstanceForCurrentProcess)( | ||
| 514 | 		_Out_ ISetupInstance** ppInstance | ||
| 515 | 		) = 0; | ||
| 516 | |||
| 517 | 	/// <summary> | ||
| 518 | 	/// Gets the instance for the given path. | ||
| 519 | 	/// </summary> | ||
| 520 | 	/// <param name="ppInstance">The instance for the given path.</param> | ||
| 521 | 	/// <returns> | ||
| 522 | 	/// The instance for the given path, or E_NOTFOUND if not found. | ||
| 523 | 	/// The <see cref="ISetupInstance::GetState"/> may indicate the instance is invalid. | ||
| 524 | 	/// </returns> | ||
| 525 | 	/// <remarks> | ||
| 526 | 	/// The returned instance may not be launchable. | ||
| 527 | 	/// </remarks> | ||
| 528 | 	STDMETHOD(GetInstanceForPath)( | ||
| 529 | 		_In_z_ LPCWSTR wzPath, | ||
| 530 | 		_Out_ ISetupInstance** ppInstance | ||
| 531 | 		) = 0; | ||
| 532 | 	}; | ||
| 533 | #endif | ||
| 534 | |||
| 535 | 	EXTERN_C const IID IID_ISetupConfiguration2; | ||
| 536 | |||
| 537 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 538 | 	/// <summary> | ||
| 539 | 	/// Gets information about product instances. | ||
| 540 | 	/// </summary> | ||
| 541 | 	struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration | ||
| 542 | 	{ | ||
| 543 | 		/// <summary> | ||
| 544 | 		/// Enumerates all product instances. | ||
| 545 | 		/// </summary> | ||
| 546 | 		/// <param name="ppEnumInstances">An enumeration of all product instances.</param> | ||
| 547 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 548 | 		STDMETHOD(EnumAllInstances)( | ||
| 549 | 			_Out_ IEnumSetupInstances** ppEnumInstances | ||
| 550 | 			) = 0; | ||
| 551 | 	}; | ||
| 552 | #endif | ||
| 553 | |||
| 554 | 	EXTERN_C const IID IID_ISetupPackageReference; | ||
| 555 | |||
| 556 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 557 | 	/// <summary> | ||
| 558 | 	/// A reference to a package. | ||
| 559 | 	/// </summary> | ||
| 560 | 	struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown | ||
| 561 | 	{ | ||
| 562 | 		/// <summary> | ||
| 563 | 		/// Gets the general package identifier. | ||
| 564 | 		/// </summary> | ||
| 565 | 		/// <param name="pbstrId">The general package identifier.</param> | ||
| 566 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 567 | 		STDMETHOD(GetId)( | ||
| 568 | 			_Out_ BSTR* pbstrId | ||
| 569 | 			) = 0; | ||
| 570 | |||
| 571 | 	/// <summary> | ||
| 572 | 	/// Gets the version of the package. | ||
| 573 | 	/// </summary> | ||
| 574 | 	/// <param name="pbstrVersion">The version of the package.</param> | ||
| 575 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 576 | 	STDMETHOD(GetVersion)( | ||
| 577 | 		_Out_ BSTR* pbstrVersion | ||
| 578 | 		) = 0; | ||
| 579 | |||
| 580 | 	/// <summary> | ||
| 581 | 	/// Gets the target process architecture of the package. | ||
| 582 | 	/// </summary> | ||
| 583 | 	/// <param name="pbstrChip">The target process architecture of the package.</param> | ||
| 584 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 585 | 	STDMETHOD(GetChip)( | ||
| 586 | 		_Out_ BSTR* pbstrChip | ||
| 587 | 		) = 0; | ||
| 588 | |||
| 589 | 	/// <summary> | ||
| 590 | 	/// Gets the language and optional region identifier. | ||
| 591 | 	/// </summary> | ||
| 592 | 	/// <param name="pbstrLanguage">The language and optional region identifier.</param> | ||
| 593 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 594 | 	STDMETHOD(GetLanguage)( | ||
| 595 | 		_Out_ BSTR* pbstrLanguage | ||
| 596 | 		) = 0; | ||
| 597 | |||
| 598 | 	/// <summary> | ||
| 599 | 	/// Gets the build branch of the package. | ||
| 600 | 	/// </summary> | ||
| 601 | 	/// <param name="pbstrBranch">The build branch of the package.</param> | ||
| 602 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 603 | 	STDMETHOD(GetBranch)( | ||
| 604 | 		_Out_ BSTR* pbstrBranch | ||
| 605 | 		) = 0; | ||
| 606 | |||
| 607 | 	/// <summary> | ||
| 608 | 	/// Gets the type of the package. | ||
| 609 | 	/// </summary> | ||
| 610 | 	/// <param name="pbstrType">The type of the package.</param> | ||
| 611 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 612 | 	STDMETHOD(GetType)( | ||
| 613 | 		_Out_ BSTR* pbstrType | ||
| 614 | 		) = 0; | ||
| 615 | |||
| 616 | 	/// <summary> | ||
| 617 | 	/// Gets the unique identifier consisting of all defined tokens. | ||
| 618 | 	/// </summary> | ||
| 619 | 	/// <param name="pbstrUniqueId">The unique identifier consisting of all defined tokens.</param> | ||
| 620 | 	/// <returns>Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required).</returns> | ||
| 621 | 	STDMETHOD(GetUniqueId)( | ||
| 622 | 		_Out_ BSTR* pbstrUniqueId | ||
| 623 | 		) = 0; | ||
| 624 | |||
| 625 | 	/// <summary> | ||
| 626 | 	/// Gets a value indicating whether the package refers to an external extension. | ||
| 627 | 	/// </summary> | ||
| 628 | 	/// <param name="pfIsExtension">A value indicating whether the package refers to an external extension.</param> | ||
| 629 | 	/// <returns>Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required).</returns> | ||
| 630 | 	STDMETHOD(GetIsExtension)( | ||
| 631 | 		_Out_ VARIANT_BOOL* pfIsExtension | ||
| 632 | 		) = 0; | ||
| 633 | 	}; | ||
| 634 | #endif | ||
| 635 | |||
| 636 | 	EXTERN_C const IID IID_ISetupHelper; | ||
| 637 | |||
| 638 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 639 | 	/// <summary> | ||
| 640 | 	/// Helper functions. | ||
| 641 | 	/// </summary> | ||
| 642 | 	/// <remarks> | ||
| 643 | 	/// You can query for this interface from the <see cref="SetupConfiguration"/> class. | ||
| 644 | 	/// </remarks> | ||
| 645 | 	struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") DECLSPEC_NOVTABLE ISetupHelper : public IUnknown | ||
| 646 | 	{ | ||
| 647 | 		/// <summary> | ||
| 648 | 		/// Parses a dotted quad version string into a 64-bit unsigned integer. | ||
| 649 | 		/// </summary> | ||
| 650 | 		/// <param name="pwszVersion">The dotted quad version string to parse, e.g. 1.2.3.4.</param> | ||
| 651 | 		/// <param name="pullVersion">A 64-bit unsigned integer representing the version. You can compare this to other versions.</param> | ||
| 652 | 		/// <returns>Standard HRESULT indicating success or failure, including E_INVALIDARG if the version is not valid.</returns> | ||
| 653 | 		STDMETHOD(ParseVersion)( | ||
| 654 | 			_In_ LPCOLESTR pwszVersion, | ||
| 655 | 			_Out_ PULONGLONG pullVersion | ||
| 656 | 			) = 0; | ||
| 657 | |||
| 658 | 	/// <summary> | ||
| 659 | 	/// Parses a dotted quad version string into a 64-bit unsigned integer. | ||
| 660 | 	/// </summary> | ||
| 661 | 	/// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param> | ||
| 662 | 	/// <param name="pullMinVersion">A 64-bit unsigned integer representing the minimum version, which may be 0. You can compare this to other versions.</param> | ||
| 663 | 	/// <param name="pullMaxVersion">A 64-bit unsigned integer representing the maximum version, which may be MAXULONGLONG. You can compare this to other versions.</param> | ||
| 664 | 	/// <returns>Standard HRESULT indicating success or failure, including E_INVALIDARG if the version range is not valid.</returns> | ||
| 665 | 	STDMETHOD(ParseVersionRange)( | ||
| 666 | 		_In_ LPCOLESTR pwszVersionRange, | ||
| 667 | 		_Out_ PULONGLONG pullMinVersion, | ||
| 668 | 		_Out_ PULONGLONG pullMaxVersion | ||
| 669 | 		) = 0; | ||
| 670 | 	}; | ||
| 671 | #endif | ||
| 672 | |||
| 673 | 	EXTERN_C const IID IID_ISetupErrorState; | ||
| 674 | |||
| 675 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 676 | 	/// <summary> | ||
| 677 | 	/// Information about the error state of an instance. | ||
| 678 | 	/// </summary> | ||
| 679 | 	struct DECLSPEC_UUID("46DCCD94-A287-476A-851E-DFBC2FFDBC20") DECLSPEC_NOVTABLE ISetupErrorState : public IUnknown | ||
| 680 | 	{ | ||
| 681 | 		/// <summary> | ||
| 682 | 		/// Gets an array of failed package references. | ||
| 683 | 		/// </summary> | ||
| 684 | 		/// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupFailedPackageReference"/>, if packages have failed.</param> | ||
| 685 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 686 | 		STDMETHOD(GetFailedPackages)( | ||
| 687 | 			_Outptr_result_maybenull_ LPSAFEARRAY* ppsaFailedPackages | ||
| 688 | 			) = 0; | ||
| 689 | |||
| 690 | 	/// <summary> | ||
| 691 | 	/// Gets an array of skipped package references. | ||
| 692 | 	/// </summary> | ||
| 693 | 	/// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/>, if packages have been skipped.</param> | ||
| 694 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 695 | 	STDMETHOD(GetSkippedPackages)( | ||
| 696 | 		_Outptr_result_maybenull_ LPSAFEARRAY* ppsaSkippedPackages | ||
| 697 | 		) = 0; | ||
| 698 | 	}; | ||
| 699 | #endif | ||
| 700 | |||
| 701 | 	EXTERN_C const IID IID_ISetupErrorState2; | ||
| 702 | |||
| 703 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 704 | 	/// <summary> | ||
| 705 | 	/// Information about the error state of an instance. | ||
| 706 | 	/// </summary> | ||
| 707 | 	struct DECLSPEC_UUID("9871385B-CA69-48F2-BC1F-7A37CBF0B1EF") DECLSPEC_NOVTABLE ISetupErrorState2 : public ISetupErrorState | ||
| 708 | 	{ | ||
| 709 | 		/// <summary> | ||
| 710 | 		/// Gets the path to the error log. | ||
| 711 | 		/// </summary> | ||
| 712 | 		/// <param name="pbstrChip">The path to the error log.</param> | ||
| 713 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 714 | 		STDMETHOD(GetErrorLogFilePath)( | ||
| 715 | 			_Outptr_result_maybenull_ BSTR* pbstrErrorLogFilePath | ||
| 716 | 			) = 0; | ||
| 717 | |||
| 718 | 	/// <summary> | ||
| 719 | 	/// Gets the path to the main setup log. | ||
| 720 | 	/// </summary> | ||
| 721 | 	/// <param name="pbstrChip">The path to the main setup log.</param> | ||
| 722 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 723 | 	STDMETHOD(GetLogFilePath)( | ||
| 724 | 		_Outptr_result_maybenull_ BSTR* pbstrLogFilePath | ||
| 725 | 		) = 0; | ||
| 726 | 	}; | ||
| 727 | #endif | ||
| 728 | |||
| 729 | 	EXTERN_C const IID IID_ISetupFailedPackageReference; | ||
| 730 | |||
| 731 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 732 | 	/// <summary> | ||
| 733 | 	/// A reference to a failed package. | ||
| 734 | 	/// </summary> | ||
| 735 | 	struct DECLSPEC_UUID("E73559CD-7003-4022-B134-27DC650B280F") DECLSPEC_NOVTABLE ISetupFailedPackageReference : public ISetupPackageReference | ||
| 736 | 	{ | ||
| 737 | 	}; | ||
| 738 | |||
| 739 | #endif | ||
| 740 | |||
| 741 | 	EXTERN_C const IID IID_ISetupFailedPackageReference2; | ||
| 742 | |||
| 743 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 744 | 	/// <summary> | ||
| 745 | 	/// A reference to a failed package. | ||
| 746 | 	/// </summary> | ||
| 747 | 	struct DECLSPEC_UUID("0FAD873E-E874-42E3-B268-4FE2F096B9CA") DECLSPEC_NOVTABLE ISetupFailedPackageReference2 : public ISetupFailedPackageReference | ||
| 748 | 	{ | ||
| 749 | 		/// <summary> | ||
| 750 | 		/// Gets the path to the optional package log. | ||
| 751 | 		/// </summary> | ||
| 752 | 		/// <param name="pbstrId">The path to the optional package log.</param> | ||
| 753 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 754 | 		STDMETHOD(GetLogFilePath)( | ||
| 755 | 			_Outptr_result_maybenull_ BSTR* pbstrLogFilePath | ||
| 756 | 			) = 0; | ||
| 757 | |||
| 758 | 	/// <summary> | ||
| 759 | 	/// Gets the description of the package failure. | ||
| 760 | 	/// </summary> | ||
| 761 | 	/// <param name="pbstrId">The description of the package failure.</param> | ||
| 762 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 763 | 	STDMETHOD(GetDescription)( | ||
| 764 | 		_Outptr_result_maybenull_ BSTR* pbstrDescription | ||
| 765 | 		) = 0; | ||
| 766 | |||
| 767 | 	/// <summary> | ||
| 768 | 	/// Gets the signature to use for feedback reporting. | ||
| 769 | 	/// </summary> | ||
| 770 | 	/// <param name="pbstrId">The signature to use for feedback reporting.</param> | ||
| 771 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 772 | 	STDMETHOD(GetSignature)( | ||
| 773 | 		_Outptr_result_maybenull_ BSTR* pbstrSignature | ||
| 774 | 		) = 0; | ||
| 775 | |||
| 776 | 	/// <summary> | ||
| 777 | 	/// Gets the array of details for this package failure. | ||
| 778 | 	/// </summary> | ||
| 779 | 	/// <param name="ppsaDetails">Pointer to an array of details as BSTRs.</param> | ||
| 780 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 781 | 	STDMETHOD(GetDetails)( | ||
| 782 | 		_Out_ LPSAFEARRAY* ppsaDetails | ||
| 783 | 		) = 0; | ||
| 784 | |||
| 785 | 	/// <summary> | ||
| 786 | 	/// Gets an array of packages affected by this package failure. | ||
| 787 | 	/// </summary> | ||
| 788 | 	/// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/> for packages affected by this package failure. This may be NULL.</param> | ||
| 789 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 790 | 	STDMETHOD(GetAffectedPackages)( | ||
| 791 | 		_Out_ LPSAFEARRAY* ppsaAffectedPackages | ||
| 792 | 		) = 0; | ||
| 793 | 	}; | ||
| 794 | |||
| 795 | #endif | ||
| 796 | |||
| 797 | 	EXTERN_C const IID IID_ISetupPropertyStore; | ||
| 798 | |||
| 799 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 800 | 	/// <summary> | ||
| 801 | 	/// Provides named properties. | ||
| 802 | 	/// </summary> | ||
| 803 | 	/// <remarks> | ||
| 804 | 	/// You can get this from an <see cref="ISetupInstance"/>, <see cref="ISetupPackageReference"/>, or derivative. | ||
| 805 | 	/// </remarks> | ||
| 806 | 	struct DECLSPEC_UUID("C601C175-A3BE-44BC-91F6-4568D230FC83") DECLSPEC_NOVTABLE ISetupPropertyStore : public IUnknown | ||
| 807 | 	{ | ||
| 808 | 		/// <summary> | ||
| 809 | 		/// Gets an array of property names in this property store. | ||
| 810 | 		/// </summary> | ||
| 811 | 		/// <param name="ppsaNames">Pointer to an array of property names as BSTRs.</param> | ||
| 812 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 813 | 		STDMETHOD(GetNames)( | ||
| 814 | 			_Out_ LPSAFEARRAY* ppsaNames | ||
| 815 | 			) = 0; | ||
| 816 | |||
| 817 | 	/// <summary> | ||
| 818 | 	/// Gets the value of a named property in this property store. | ||
| 819 | 	/// </summary> | ||
| 820 | 	/// <param name="pwszName">The name of the property to get.</param> | ||
| 821 | 	/// <param name="pvtValue">The value of the property.</param> | ||
| 822 | 	/// <returns>Standard HRESULT indicating success or failure, including E_NOTFOUND if the property is not defined or E_NOTSUPPORTED if the property type is not supported.</returns> | ||
| 823 | 	STDMETHOD(GetValue)( | ||
| 824 | 		_In_ LPCOLESTR pwszName, | ||
| 825 | 		_Out_ LPVARIANT pvtValue | ||
| 826 | 		) = 0; | ||
| 827 | 	}; | ||
| 828 | |||
| 829 | #endif | ||
| 830 | |||
| 831 | 	EXTERN_C const IID IID_ISetupLocalizedPropertyStore; | ||
| 832 | |||
| 833 | #if defined(__cplusplus) && !defined(CINTERFACE) | ||
| 834 | 	/// <summary> | ||
| 835 | 	/// Provides localized named properties. | ||
| 836 | 	/// </summary> | ||
| 837 | 	/// <remarks> | ||
| 838 | 	/// You can get this from an <see cref="ISetupLocalizedProperties"/>. | ||
| 839 | 	/// </remarks> | ||
| 840 | 	struct DECLSPEC_UUID("5BB53126-E0D5-43DF-80F1-6B161E5C6F6C") DECLSPEC_NOVTABLE ISetupLocalizedPropertyStore : public IUnknown | ||
| 841 | 	{ | ||
| 842 | 		/// <summary> | ||
| 843 | 		/// Gets an array of property names in this property store. | ||
| 844 | 		/// </summary> | ||
| 845 | 		/// <param name="lcid">The LCID for the property names.</param> | ||
| 846 | 		/// <param name="ppsaNames">Pointer to an array of property names as BSTRs.</param> | ||
| 847 | 		/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 848 | 		STDMETHOD(GetNames)( | ||
| 849 | 			_In_ LCID lcid, | ||
| 850 | 			_Out_ LPSAFEARRAY* ppsaNames | ||
| 851 | 			) = 0; | ||
| 852 | |||
| 853 | 	/// <summary> | ||
| 854 | 	/// Gets the value of a named property in this property store. | ||
| 855 | 	/// </summary> | ||
| 856 | 	/// <param name="pwszName">The name of the property to get.</param> | ||
| 857 | 	/// <param name="lcid">The LCID for the property.</param> | ||
| 858 | 	/// <param name="pvtValue">The value of the property.</param> | ||
| 859 | 	/// <returns>Standard HRESULT indicating success or failure, including E_NOTFOUND if the property is not defined or E_NOTSUPPORTED if the property type is not supported.</returns> | ||
| 860 | 	STDMETHOD(GetValue)( | ||
| 861 | 		_In_ LPCOLESTR pwszName, | ||
| 862 | 		_In_ LCID lcid, | ||
| 863 | 		_Out_ LPVARIANT pvtValue | ||
| 864 | 		) = 0; | ||
| 865 | 	}; | ||
| 866 | |||
| 867 | #endif | ||
| 868 | |||
| 869 | 	// Class declarations | ||
| 870 | 	// | ||
| 871 | 	EXTERN_C const CLSID CLSID_SetupConfiguration; | ||
| 872 | |||
| 873 | #ifdef __cplusplus | ||
| 874 | |||
| 875 | #ifdef __GNUC__ | ||
| 876 | __CRT_UUID_DECL(SetupConfiguration, 0x177F0C4A, 0x1CD3, 0x4DE7, 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D); | ||
| 877 | #endif | ||
| 878 | |||
| 879 | 	/// <summary> | ||
| 880 | 	/// This class implements <see cref="ISetupConfiguration"/>, <see cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>. | ||
| 881 | 	/// </summary> | ||
| 882 | 	class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration; | ||
| 883 | #endif | ||
| 884 | 	// Function declarations | ||
| 885 | 	// | ||
| 886 | 	/// <summary> | ||
| 887 | 	/// Gets an <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine. | ||
| 888 | 	/// </summary> | ||
| 889 | 	/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.</param> | ||
| 890 | 	/// <param name="pReserved">Reserved for future use.</param> | ||
| 891 | 	/// <returns>Standard HRESULT indicating success or failure.</returns> | ||
| 892 | 	STDMETHODIMP GetSetupConfiguration( | ||
| 893 | 		_Out_ ISetupConfiguration** ppConfiguration, | ||
| 894 | 		_Reserved_ LPVOID pReserved | ||
| 895 | 	); | ||
| 896 | |||
| 897 | #ifdef __cplusplus | ||
| 898 | } | ||
| 899 | #endif | ||
| 900 | |||
| 901 | _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); | ||
| 902 | _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); | ||
| 903 | _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); | ||
| 904 | _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); | ||
| 905 | _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); | ||
| 906 | _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); | ||
| 907 | _COM_SMARTPTR_TYPEDEF(ISetupPackageReference, __uuidof(ISetupPackageReference)); | ||
| 908 | _COM_SMARTPTR_TYPEDEF(ISetupPropertyStore, __uuidof(ISetupPropertyStore)); | ||
| 909 | _COM_SMARTPTR_TYPEDEF(ISetupInstanceCatalog, __uuidof(ISetupInstanceCatalog)); | ||
src/windows_sdk.cpp deleted-387| ... | @@ -1,387 +0,0 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "windows_sdk.h" | ||
| 9 | |||
| 10 | #if defined(_WIN32) | ||
| 11 | |||
| 12 | #include "windows_com.hpp" | ||
| 13 | #include <inttypes.h> | ||
| 14 | #include <assert.h> | ||
| 15 | |||
| 16 | const char *ZIG_WINDOWS_KIT_REG_KEY = "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots"; | ||
| 17 | |||
| 18 | struct ZigWindowsSDKPrivate { | ||
| 19 | ZigWindowsSDK base; | ||
| 20 | }; | ||
| 21 | |||
| 22 | enum NativeArch { | ||
| 23 | NativeArchArm, | ||
| 24 | NativeArchx86, | ||
| 25 | NativeArchx86_64, | ||
| 26 | NativeArchAarch64, | ||
| 27 | }; | ||
| 28 | |||
| 29 | #if defined(_M_ARM) || defined(__arm_) | ||
| 30 | static const NativeArch native_arch = NativeArchArm; | ||
| 31 | #elif defined(_M_IX86) || defined(__i386__) | ||
| 32 | static const NativeArch native_arch = NativeArchx86; | ||
| 33 | #elif defined(_M_X64) || defined(__x86_64__) | ||
| 34 | static const NativeArch native_arch = NativeArchx86_64; | ||
| 35 | #elif defined(_M_ARM64) || defined(__aarch64__) | ||
| 36 | static const NativeArch native_arch = NativeArchAarch64; | ||
| 37 | #else | ||
| 38 | #error unsupported architecture | ||
| 39 | #endif | ||
| 40 | |||
| 41 | void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) { | ||
| 42 | if (sdk == nullptr) { | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | free((void*)sdk->path10_ptr); | ||
| 46 | free((void*)sdk->version10_ptr); | ||
| 47 | free((void*)sdk->path81_ptr); | ||
| 48 | free((void*)sdk->version81_ptr); | ||
| 49 | free((void*)sdk->msvc_lib_dir_ptr); | ||
| 50 | } | ||
| 51 | |||
| 52 | static ZigFindWindowsSdkError find_msvc_lib_dir(ZigWindowsSDKPrivate *priv) { | ||
| 53 | //COM Smart Pointers requires explicit scope | ||
| 54 | { | ||
| 55 | HRESULT rc = CoInitializeEx(NULL, COINIT_MULTITHREADED); | ||
| 56 | if (rc != S_OK && rc != S_FALSE) { | ||
| 57 | goto com_done; | ||
| 58 | } | ||
| 59 | |||
| 60 | //This COM class is installed when a VS2017 | ||
| 61 | ISetupConfigurationPtr setup_config; | ||
| 62 | rc = setup_config.CreateInstance(__uuidof(SetupConfiguration)); | ||
| 63 | if (rc != S_OK) { | ||
| 64 | goto com_done; | ||
| 65 | } | ||
| 66 | |||
| 67 | IEnumSetupInstancesPtr all_instances; | ||
| 68 | rc = setup_config->EnumInstances(&all_instances); | ||
| 69 | if (rc != S_OK) { | ||
| 70 | goto com_done; | ||
| 71 | } | ||
| 72 | |||
| 73 | ISetupInstance* curr_instance; | ||
| 74 | ULONG found_inst; | ||
| 75 | while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) { | ||
| 76 | BSTR bstr_inst_path; | ||
| 77 | rc = curr_instance->GetInstallationPath(&bstr_inst_path); | ||
| 78 | if (rc != S_OK) { | ||
| 79 | goto com_done; | ||
| 80 | } | ||
| 81 | //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length | ||
| 82 | //TODO call an actual function to do this | ||
| 83 | UINT bstr_path_len = *((UINT*)bstr_inst_path - 1); | ||
| 84 | ULONG tmp_path_len = bstr_path_len / 2 + 1; | ||
| 85 | char* conv_path = (char*)bstr_inst_path; | ||
| 86 | // TODO don't use alloca | ||
| 87 | char *tmp_path = (char*)alloca(tmp_path_len); | ||
| 88 | memset(tmp_path, 0, tmp_path_len); | ||
| 89 | uint32_t c = 0; | ||
| 90 | for (uint32_t i = 0; i < bstr_path_len; i += 2) { | ||
| 91 | tmp_path[c] = conv_path[i]; | ||
| 92 | ++c; | ||
| 93 | assert(c != tmp_path_len); | ||
| 94 | } | ||
| 95 | char output_path[4096]; | ||
| 96 | output_path[0] = 0; | ||
| 97 | char *out_append_ptr = output_path; | ||
| 98 | |||
| 99 | out_append_ptr += sprintf(out_append_ptr, "%s\\", tmp_path); | ||
| 100 | |||
| 101 | char tmp_buf[4096]; | ||
| 102 | sprintf(tmp_buf, "%s%s", output_path, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); | ||
| 103 | FILE* tools_file = fopen(tmp_buf, "rb"); | ||
| 104 | if (!tools_file) { | ||
| 105 | goto com_done; | ||
| 106 | } | ||
| 107 | memset(tmp_path, 0, tmp_path_len); | ||
| 108 | fgets(tmp_path, tmp_path_len, tools_file); | ||
| 109 | strtok(tmp_path, " \r\n"); | ||
| 110 | fclose(tools_file); | ||
| 111 | out_append_ptr += sprintf(out_append_ptr, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path); | ||
| 112 | switch (native_arch) { | ||
| 113 | case NativeArchx86: | ||
| 114 | out_append_ptr += sprintf(out_append_ptr, "x86\\"); | ||
| 115 | break; | ||
| 116 | case NativeArchx86_64: | ||
| 117 | out_append_ptr += sprintf(out_append_ptr, "x64\\"); | ||
| 118 | break; | ||
| 119 | case NativeArchArm: | ||
| 120 | out_append_ptr += sprintf(out_append_ptr, "arm\\"); | ||
| 121 | break; | ||
| 122 | case NativeArchAarch64: | ||
| 123 | out_append_ptr += sprintf(out_append_ptr, "arm64\\"); | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | sprintf(tmp_buf, "%s%s", output_path, "vcruntime.lib"); | ||
| 127 | |||
| 128 | if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) { | ||
| 129 | priv->base.msvc_lib_dir_ptr = strdup(output_path); | ||
| 130 | if (priv->base.msvc_lib_dir_ptr == nullptr) { | ||
| 131 | return ZigFindWindowsSdkErrorOutOfMemory; | ||
| 132 | } | ||
| 133 | priv->base.msvc_lib_dir_len = strlen(priv->base.msvc_lib_dir_ptr); | ||
| 134 | return ZigFindWindowsSdkErrorNone; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | com_done:; | ||
| 140 | HKEY key; | ||
| 141 | HRESULT rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0, | ||
| 142 | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key); | ||
| 143 | if (rc != ERROR_SUCCESS) { | ||
| 144 | return ZigFindWindowsSdkErrorNotFound; | ||
| 145 | } | ||
| 146 | |||
| 147 | DWORD dw_type = 0; | ||
| 148 | DWORD cb_data = 0; | ||
| 149 | rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data); | ||
| 150 | if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) { | ||
| 151 | return ZigFindWindowsSdkErrorNotFound; | ||
| 152 | } | ||
| 153 | |||
| 154 | char tmp_buf[4096]; | ||
| 155 | |||
| 156 | RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)tmp_buf, &cb_data); | ||
| 157 | // RegQueryValueExA returns the length of the string INCLUDING the null terminator | ||
| 158 | char *tmp_buf_append_ptr = tmp_buf + (cb_data - 1); | ||
| 159 | tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "VC\\Lib\\"); | ||
| 160 | switch (native_arch) { | ||
| 161 | case NativeArchx86: | ||
| 162 | //x86 is in the root of the Lib folder | ||
| 163 | break; | ||
| 164 | case NativeArchx86_64: | ||
| 165 | tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "amd64\\"); | ||
| 166 | break; | ||
| 167 | case NativeArchArm: | ||
| 168 | tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "arm\\"); | ||
| 169 | break; | ||
| 170 | case NativeArchAarch64: | ||
| 171 | tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "arm64\\"); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | char *output_path = strdup(tmp_buf); | ||
| 176 | if (output_path == nullptr) { | ||
| 177 | return ZigFindWindowsSdkErrorOutOfMemory; | ||
| 178 | } | ||
| 179 | |||
| 180 | tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "vcruntime.lib"); | ||
| 181 | |||
| 182 | if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) { | ||
| 183 | priv->base.msvc_lib_dir_ptr = output_path; | ||
| 184 | priv->base.msvc_lib_dir_len = strlen(output_path); | ||
| 185 | return ZigFindWindowsSdkErrorNone; | ||
| 186 | } else { | ||
| 187 | free(output_path); | ||
| 188 | return ZigFindWindowsSdkErrorNotFound; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | static ZigFindWindowsSdkError find_10_version(ZigWindowsSDKPrivate *priv) { | ||
| 193 | if (priv->base.path10_ptr == nullptr) { | ||
| 194 | return ZigFindWindowsSdkErrorNone; | ||
| 195 | } | ||
| 196 | |||
| 197 | 	char reg_query[MAX_PATH] = { 0 }; | ||
| 198 | 	int n = snprintf(reg_query, MAX_PATH, "%s\\%s.0\\Installed Options", ZIG_WINDOWS_KIT_REG_KEY, priv->base.version10_ptr); | ||
| 199 | 	if (n < 0 || n >= MAX_PATH) { | ||
| 200 | 		return ZigFindWindowsSdkErrorPathTooLong; | ||
| 201 | 	} | ||
| 202 | |||
| 203 | 	HKEY options_key; | ||
| 204 | 	HRESULT rc; | ||
| 205 | 	rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_query, 0, | ||
| 206 | 		KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &options_key); | ||
| 207 | 	if (rc != ERROR_SUCCESS) { | ||
| 208 | 		return ZigFindWindowsSdkErrorNotFound; | ||
| 209 | 	} | ||
| 210 | |||
| 211 | 	const char *option_name = nullptr; | ||
| 212 | 	switch (native_arch) { | ||
| 213 | 	case NativeArchArm: | ||
| 214 | 		option_name = "OptionId.DesktopCPParm"; | ||
| 215 | 		break; | ||
| 216 | 	case NativeArchAarch64: | ||
| 217 | 		option_name = "OptionId.DesktopCPParm64"; | ||
| 218 | 		break; | ||
| 219 | 	case NativeArchx86_64: | ||
| 220 | 		option_name = "OptionId.DesktopCPPx64"; | ||
| 221 | 		break; | ||
| 222 | 	case NativeArchx86: | ||
| 223 | 		option_name = "OptionId.DesktopCPPx86"; | ||
| 224 | 		break; | ||
| 225 | 	default: | ||
| 226 | 		return ZigFindWindowsSdkErrorNotFound; | ||
| 227 | 	} | ||
| 228 | |||
| 229 | 	DWORD val_sz = sizeof(DWORD); | ||
| 230 | 	DWORD reg_val = 0; | ||
| 231 | 	DWORD type = REG_DWORD; | ||
| 232 | 	rc = RegQueryValueEx(options_key, option_name, NULL, &type, (LPBYTE)&reg_val, &val_sz); | ||
| 233 | 	if (rc != ERROR_SUCCESS || reg_val != 1) { | ||
| 234 | 		return ZigFindWindowsSdkErrorNotFound; | ||
| 235 | 	} | ||
| 236 | return ZigFindWindowsSdkErrorNone; | ||
| 237 | } | ||
| 238 | |||
| 239 | static ZigFindWindowsSdkError find_81_version(ZigWindowsSDKPrivate *priv) { | ||
| 240 | if (priv->base.path81_ptr == nullptr) { | ||
| 241 | return ZigFindWindowsSdkErrorNone; | ||
| 242 | } | ||
| 243 | |||
| 244 | char sdk_lib_dir[4096]; | ||
| 245 | int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\winv*", priv->base.path81_ptr); | ||
| 246 | if (n < 0 || n >= 4096) { | ||
| 247 | return ZigFindWindowsSdkErrorPathTooLong; | ||
| 248 | } | ||
| 249 | |||
| 250 | // enumerate files in sdk path looking for latest version | ||
| 251 | WIN32_FIND_DATA ffd; | ||
| 252 | HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd); | ||
| 253 | if (hFind == INVALID_HANDLE_VALUE) { | ||
| 254 | return ZigFindWindowsSdkErrorNotFound; | ||
| 255 | } | ||
| 256 | int v0 = 0, v1 = 0; | ||
| 257 | for (;;) { | ||
| 258 | if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | ||
| 259 | int c0 = 0, c1 = 0; | ||
| 260 | sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1); | ||
| 261 | |||
| 262 | if ( (c0 > v0) || (c0 == v0 && c1 > v1) ) { | ||
| 263 | v0 = c0, v1 = c1; | ||
| 264 | free((void*)priv->base.version81_ptr); | ||
| 265 | priv->base.version81_ptr = strdup(ffd.cFileName); | ||
| 266 | if (priv->base.version81_ptr == nullptr) { | ||
| 267 | FindClose(hFind); | ||
| 268 | return ZigFindWindowsSdkErrorOutOfMemory; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | } | ||
| 272 | if (FindNextFile(hFind, &ffd) == 0) { | ||
| 273 | FindClose(hFind); | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | priv->base.version81_len = strlen(priv->base.version81_ptr); | ||
| 278 | return ZigFindWindowsSdkErrorNone; | ||
| 279 | } | ||
| 280 | |||
| 281 | ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) { | ||
| 282 | ZigWindowsSDKPrivate *priv = (ZigWindowsSDKPrivate*)calloc(1, sizeof(ZigWindowsSDKPrivate)); | ||
| 283 | if (priv == nullptr) { | ||
| 284 | return ZigFindWindowsSdkErrorOutOfMemory; | ||
| 285 | } | ||
| 286 | |||
| 287 | 	HRESULT rc; | ||
| 288 | |||
| 289 | 	//note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed | ||
| 290 | 	HKEY roots_key; | ||
| 291 | 	rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ZIG_WINDOWS_KIT_REG_KEY, 0, | ||
| 292 | 		KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &roots_key); | ||
| 293 | 	if (rc != ERROR_SUCCESS) { | ||
| 294 | 		zig_free_windows_sdk(&priv->base); | ||
| 295 | 		return ZigFindWindowsSdkErrorNotFound; | ||
| 296 | 	} | ||
| 297 | |||
| 298 | { | ||
| 299 | 		HKEY v10_key; | ||
| 300 | 		rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0", 0, | ||
| 301 | 			KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &v10_key); | ||
| 302 | 		if (rc != ERROR_SUCCESS) { | ||
| 303 | 			goto find_win10_sdk_done; | ||
| 304 | 		} | ||
| 305 | |||
| 306 | DWORD tmp_buf_len = MAX_PATH; | ||
| 307 | priv->base.path10_ptr = (const char *)calloc(tmp_buf_len, 1); | ||
| 308 | if (priv->base.path10_ptr == nullptr) { | ||
| 309 | zig_free_windows_sdk(&priv->base); | ||
| 310 | return ZigFindWindowsSdkErrorOutOfMemory; | ||
| 311 | } | ||
| 312 | rc = RegQueryValueEx(v10_key, "InstallationFolder", NULL, NULL, (LPBYTE)priv->base.path10_ptr, &tmp_buf_len); | ||
| 313 | if (rc == ERROR_SUCCESS) { | ||
| 314 | priv->base.path10_len = tmp_buf_len - 1; | ||
| 315 | if (priv->base.path10_ptr[priv->base.path10_len - 1] == '\\') { | ||
| 316 | priv->base.path10_len -= 1; | ||
| 317 | } | ||
| 318 | } else { | ||
| 319 | free((void*)priv->base.path10_ptr); | ||
| 320 | priv->base.path10_ptr = nullptr; | ||
| 321 | } | ||
| 322 | |||
| 323 | 		priv->base.version10_ptr = (const char*)calloc(tmp_buf_len, 1); | ||
| 324 | 		rc = RegQueryValueEx(v10_key, "ProductVersion", NULL, NULL, (LPBYTE)priv->base.version10_ptr, &tmp_buf_len); | ||
| 325 | 		if (rc == ERROR_SUCCESS) { | ||
| 326 | 			snprintf((char*)priv->base.version10_ptr, MAX_PATH, "%s.0", priv->base.version10_ptr); | ||
| 327 | 			priv->base.version10_len = tmp_buf_len - 1 + 2; // note(dimenus): Microsoft doesn't include the .0 in the ProductVersion key.... | ||
| 328 | 		} else { | ||
| 329 | 			free((void*)priv->base.version10_ptr); | ||
| 330 | 			priv->base.version10_ptr = nullptr; | ||
| 331 | 		} | ||
| 332 | } | ||
| 333 | 	find_win10_sdk_done: | ||
| 334 | { | ||
| 335 | DWORD tmp_buf_len = MAX_PATH; | ||
| 336 | priv->base.path81_ptr = (const char *)calloc(tmp_buf_len, 1); | ||
| 337 | if (priv->base.path81_ptr == nullptr) { | ||
| 338 | zig_free_windows_sdk(&priv->base); | ||
| 339 | return ZigFindWindowsSdkErrorOutOfMemory; | ||
| 340 | } | ||
| 341 | rc = RegQueryValueEx(roots_key, "KitsRoot81", NULL, NULL, (LPBYTE)priv->base.path81_ptr, &tmp_buf_len); | ||
| 342 | if (rc == ERROR_SUCCESS) { | ||
| 343 | priv->base.path81_len = tmp_buf_len - 1; | ||
| 344 | if (priv->base.path81_ptr[priv->base.path81_len - 1] == '\\') { | ||
| 345 | priv->base.path81_len -= 1; | ||
| 346 | } | ||
| 347 | } else { | ||
| 348 | free((void*)priv->base.path81_ptr); | ||
| 349 | priv->base.path81_ptr = nullptr; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | { | ||
| 354 | ZigFindWindowsSdkError err = find_10_version(priv); | ||
| 355 | if (err == ZigFindWindowsSdkErrorOutOfMemory) { | ||
| 356 | zig_free_windows_sdk(&priv->base); | ||
| 357 | return err; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | { | ||
| 361 | ZigFindWindowsSdkError err = find_81_version(priv); | ||
| 362 | if (err == ZigFindWindowsSdkErrorOutOfMemory) { | ||
| 363 | zig_free_windows_sdk(&priv->base); | ||
| 364 | return err; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | { | ||
| 369 | ZigFindWindowsSdkError err = find_msvc_lib_dir(priv); | ||
| 370 | if (err == ZigFindWindowsSdkErrorOutOfMemory) { | ||
| 371 | zig_free_windows_sdk(&priv->base); | ||
| 372 | return err; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | *out_sdk = &priv->base; | ||
| 377 | return ZigFindWindowsSdkErrorNone; | ||
| 378 | } | ||
| 379 | |||
| 380 | #else | ||
| 381 | |||
| 382 | void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {} | ||
| 383 | ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) { | ||
| 384 | return ZigFindWindowsSdkErrorNotFound; | ||
| 385 | } | ||
| 386 | |||
| 387 | #endif | ||
src/windows_sdk.h deleted-51| ... | @@ -1,51 +0,0 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_WINDOWS_SDK_H | ||
| 9 | #define ZIG_WINDOWS_SDK_H | ||
| 10 | |||
| 11 | #ifdef __cplusplus | ||
| 12 | #define ZIG_EXTERN_C extern "C" | ||
| 13 | #else | ||
| 14 | #define ZIG_EXTERN_C | ||
| 15 | #endif | ||
| 16 | |||
| 17 | #include <stddef.h> | ||
| 18 | |||
| 19 | // ABI warning - src/windows_sdk.zig | ||
| 20 | struct ZigWindowsSDK { | ||
| 21 | const char *path10_ptr; | ||
| 22 | size_t path10_len; | ||
| 23 | |||
| 24 | const char *version10_ptr; | ||
| 25 | size_t version10_len; | ||
| 26 | |||
| 27 | const char *path81_ptr; | ||
| 28 | size_t path81_len; | ||
| 29 | |||
| 30 | const char *version81_ptr; | ||
| 31 | size_t version81_len; | ||
| 32 | |||
| 33 | const char *msvc_lib_dir_ptr; | ||
| 34 | size_t msvc_lib_dir_len; | ||
| 35 | }; | ||
| 36 | |||
| 37 | // ABI warning - src/windows_sdk.zig | ||
| 38 | enum ZigFindWindowsSdkError { | ||
| 39 | ZigFindWindowsSdkErrorNone, | ||
| 40 | ZigFindWindowsSdkErrorOutOfMemory, | ||
| 41 | ZigFindWindowsSdkErrorNotFound, | ||
| 42 | ZigFindWindowsSdkErrorPathTooLong, | ||
| 43 | }; | ||
| 44 | |||
| 45 | // ABI warning - src/windows_sdk.zig | ||
| 46 | ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk); | ||
| 47 | |||
| 48 | // ABI warning - src/windows_sdk.zig | ||
| 49 | ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk); | ||
| 50 | |||
| 51 | #endif | ||
src/windows_sdk.zig+754-26| ... | @@ -1,27 +1,755 @@ | ... | @@ -1,27 +1,755 @@ |
| 1 | // C API bindings for src/windows_sdk.h | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); | |
| 3 | pub const ZigWindowsSDK = extern struct { | 3 | |
| 4 | path10_ptr: ?[*]const u8, | 4 | const windows = std.os.windows; |
| 5 | path10_len: usize, | 5 | const RRF = windows.advapi32.RRF; |
| 6 | version10_ptr: ?[*]const u8, | 6 | |
| 7 | version10_len: usize, | 7 | const WINDOWS_KIT_REG_KEY = "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots"; |
| 8 | path81_ptr: ?[*]const u8, | 8 | |
| 9 | path81_len: usize, | 9 | // https://learn.microsoft.com/en-us/windows/win32/msi/productversion |
| 10 | version81_ptr: ?[*]const u8, | 10 | const version_major_minor_max_length = "255.255".len; |
| 11 | version81_len: usize, | 11 | // note(bratishkaerik): i think ProductVersion in registry (created by Visual Studio installer) also follows this rule |
| 12 | msvc_lib_dir_ptr: ?[*]const u8, | 12 | const product_version_max_length = version_major_minor_max_length + ".65535".len; |
| 13 | msvc_lib_dir_len: usize, | 13 | |
| 14 | 14 | /// Iterates via `iterator` and collects all folders with names starting with `optional_prefix` | |
| 15 | pub const find = zig_find_windows_sdk; | 15 | /// and similar to SemVer. Returns slice of folder names sorted in descending order. |
| 16 | pub const free = zig_free_windows_sdk; | 16 | /// Caller owns result. |
| 17 | 17 | fn iterateAndFilterBySemVer(iterator: *std.fs.IterableDir.Iterator, allocator: std.mem.Allocator, comptime optional_prefix: ?[]const u8) error{ OutOfMemory, VersionNotFound }![][]const u8 { | |
| 18 | pub const FindError = enum(c_int) { | 18 | var dirs_filtered_list = std.ArrayList([]const u8).init(allocator); |
| 19 | None, | 19 | errdefer { |
| 20 | OutOfMemory, | 20 | for (dirs_filtered_list.items) |filtered_dir| allocator.free(filtered_dir); |
| 21 | NotFound, | 21 | dirs_filtered_list.deinit(); |
| 22 | PathTooLong, | 22 | } |
| 23 | }; | 23 | |
| 24 | 24 | var normalized_name_buf: [std.fs.MAX_NAME_BYTES + ".0+build.0".len]u8 = undefined; | |
| 25 | extern fn zig_find_windows_sdk(out_sdk: **ZigWindowsSDK) FindError; | 25 | var normalized_name_fbs = std.io.fixedBufferStream(&normalized_name_buf); |
| 26 | extern fn zig_free_windows_sdk(sdk: *ZigWindowsSDK) void; | 26 | const normalized_name_w = normalized_name_fbs.writer(); |
| 27 | iterate_folder: while (true) : (normalized_name_fbs.reset()) { | ||
| 28 | const maybe_entry = iterator.next() catch continue :iterate_folder; | ||
| 29 | const entry = maybe_entry orelse break :iterate_folder; | ||
| 30 | |||
| 31 | if (entry.kind != .directory) | ||
| 32 | continue :iterate_folder; | ||
| 33 | |||
| 34 | // invalidated on next iteration | ||
| 35 | const subfolder_name = blk: { | ||
| 36 | if (comptime optional_prefix) |prefix| { | ||
| 37 | if (!std.mem.startsWith(u8, entry.name, prefix)) continue :iterate_folder; | ||
| 38 | break :blk entry.name[prefix.len..]; | ||
| 39 | } else break :blk entry.name; | ||
| 40 | }; | ||
| 41 | |||
| 42 | { // check if subfolder name looks similar to SemVer | ||
| 43 | switch (std.mem.count(u8, subfolder_name, ".")) { | ||
| 44 | 0 => normalized_name_w.print("{s}.0.0+build.0", .{subfolder_name}) catch unreachable, // 17 => 17.0.0+build.0 | ||
| 45 | 1 => if (std.mem.indexOfScalar(u8, subfolder_name, '_')) |underscore_pos| blk: { // 17.0_9e9cbb98 => 17.0.1+build.9e9cbb98 | ||
| 46 | var subfolder_name_tmp_copy_buf: [std.fs.MAX_NAME_BYTES]u8 = undefined; | ||
| 47 | const subfolder_name_tmp_copy = subfolder_name_tmp_copy_buf[0..subfolder_name.len]; | ||
| 48 | @memcpy(subfolder_name_tmp_copy, subfolder_name); | ||
| 49 | |||
| 50 | subfolder_name_tmp_copy[underscore_pos] = '.'; // 17.0_9e9cbb98 => 17.0.9e9cbb98 | ||
| 51 | var subfolder_name_parts = std.mem.splitScalar(u8, subfolder_name_tmp_copy, '.'); // [ 17, 0, 9e9cbb98 ] | ||
| 52 | |||
| 53 | const first = subfolder_name_parts.first(); // 17 | ||
| 54 | const second = subfolder_name_parts.next().?; // 0 | ||
| 55 | const third = subfolder_name_parts.rest(); // 9e9cbb98 | ||
| 56 | |||
| 57 | break :blk normalized_name_w.print("{s}.{s}.1+build.{s}", .{ first, second, third }) catch unreachable; // [ 17, 0, 9e9cbb98 ] => 17.0.1+build.9e9cbb98 | ||
| 58 | } else normalized_name_w.print("{s}.0+build.0", .{subfolder_name}) catch unreachable, // 17.0 => 17.0.0+build.0 | ||
| 59 | else => normalized_name_w.print("{s}+build.0", .{subfolder_name}) catch unreachable, // 17.0.0 => 17.0.0+build.0 | ||
| 60 | } | ||
| 61 | const subfolder_name_normalized: []const u8 = normalized_name_fbs.getWritten(); | ||
| 62 | const sem_ver = std.SemanticVersion.parse(subfolder_name_normalized); | ||
| 63 | _ = sem_ver catch continue :iterate_folder; | ||
| 64 | } | ||
| 65 | // entry.name passed check | ||
| 66 | |||
| 67 | const subfolder_name_allocated = try allocator.dupe(u8, subfolder_name); | ||
| 68 | errdefer allocator.free(subfolder_name_allocated); | ||
| 69 | try dirs_filtered_list.append(subfolder_name_allocated); | ||
| 70 | } | ||
| 71 | |||
| 72 | var dirs_filtered_slice = try dirs_filtered_list.toOwnedSlice(); | ||
| 73 | // Keep in mind that order of these names is not guaranteed by Windows, | ||
| 74 | // so we cannot just reverse or "while (popOrNull())" this ArrayList. | ||
| 75 | std.mem.sortUnstable([]const u8, dirs_filtered_slice, {}, struct { | ||
| 76 | fn desc(_: void, lhs: []const u8, rhs: []const u8) bool { | ||
| 77 | return std.mem.order(u8, lhs, rhs) == .gt; | ||
| 78 | } | ||
| 79 | }.desc); | ||
| 80 | return dirs_filtered_slice; | ||
| 81 | } | ||
| 82 | |||
| 83 | const RegistryUtf8 = struct { | ||
| 84 | key: windows.HKEY, | ||
| 85 | |||
| 86 | /// Assert that `key` is valid UTF-8 string | ||
| 87 | pub fn openKey(key: []const u8) error{KeyNotFound}!RegistryUtf8 { | ||
| 88 | const key_utf16le: [:0]const u16 = key_utf16le: { | ||
| 89 | var key_utf16le_buf: [RegistryUtf16Le.key_name_max_len]u16 = undefined; | ||
| 90 | const key_utf16le_len: usize = std.unicode.utf8ToUtf16Le(key_utf16le_buf[0..], key) catch |err| switch (err) { | ||
| 91 | error.InvalidUtf8 => unreachable, | ||
| 92 | }; | ||
| 93 | key_utf16le_buf[key_utf16le_len] = 0; | ||
| 94 | break :key_utf16le key_utf16le_buf[0..key_utf16le_len :0]; | ||
| 95 | }; | ||
| 96 | |||
| 97 | const registry_utf16le = try RegistryUtf16Le.openKey(key_utf16le); | ||
| 98 | return RegistryUtf8{ .key = registry_utf16le.key }; | ||
| 99 | } | ||
| 100 | |||
| 101 | /// Closes key, after that usage is invalid | ||
| 102 | pub fn closeKey(self: *const RegistryUtf8) void { | ||
| 103 | const return_code_int: windows.HRESULT = windows.advapi32.RegCloseKey(self.key); | ||
| 104 | const return_code: windows.Win32Error = @enumFromInt(return_code_int); | ||
| 105 | switch (return_code) { | ||
| 106 | .SUCCESS => {}, | ||
| 107 | else => {}, | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | /// Get string from registry. | ||
| 112 | /// Caller owns result. | ||
| 113 | pub fn getString(self: *const RegistryUtf8, allocator: std.mem.Allocator, subkey: []const u8, value_name: []const u8) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]u8 { | ||
| 114 | const subkey_utf16le: [:0]const u16 = subkey_utf16le: { | ||
| 115 | var subkey_utf16le_buf: [RegistryUtf16Le.key_name_max_len]u16 = undefined; | ||
| 116 | const subkey_utf16le_len: usize = std.unicode.utf8ToUtf16Le(subkey_utf16le_buf[0..], subkey) catch unreachable; | ||
| 117 | subkey_utf16le_buf[subkey_utf16le_len] = 0; | ||
| 118 | break :subkey_utf16le subkey_utf16le_buf[0..subkey_utf16le_len :0]; | ||
| 119 | }; | ||
| 120 | |||
| 121 | const value_name_utf16le: [:0]const u16 = value_name_utf16le: { | ||
| 122 | var value_name_utf16le_buf: [RegistryUtf16Le.value_name_max_len]u16 = undefined; | ||
| 123 | const value_name_utf16le_len: usize = std.unicode.utf8ToUtf16Le(value_name_utf16le_buf[0..], value_name) catch unreachable; | ||
| 124 | value_name_utf16le_buf[value_name_utf16le_len] = 0; | ||
| 125 | break :value_name_utf16le value_name_utf16le_buf[0..value_name_utf16le_len :0]; | ||
| 126 | }; | ||
| 127 | |||
| 128 | const registry_utf16le = RegistryUtf16Le{ .key = self.key }; | ||
| 129 | const value_utf16le = try registry_utf16le.getString(allocator, subkey_utf16le, value_name_utf16le); | ||
| 130 | defer allocator.free(value_utf16le); | ||
| 131 | |||
| 132 | var value_utf8: []u8 = std.unicode.utf16leToUtf8Alloc(allocator, value_utf16le) catch |err| switch (err) { | ||
| 133 | error.OutOfMemory => return error.OutOfMemory, | ||
| 134 | else => return error.StringNotFound, | ||
| 135 | }; | ||
| 136 | errdefer allocator.free(value_utf8); | ||
| 137 | |||
| 138 | return value_utf8; | ||
| 139 | } | ||
| 140 | |||
| 141 | /// Get DWORD (u32) from registry. | ||
| 142 | pub fn getDword(self: *const RegistryUtf8, subkey: []const u8, value_name: []const u8) error{ ValueNameNotFound, NotADword, DwordTooLong, DwordNotFound }!u32 { | ||
| 143 | const subkey_utf16le: [:0]const u16 = subkey_utf16le: { | ||
| 144 | var subkey_utf16le_buf: [RegistryUtf16Le.key_name_max_len]u16 = undefined; | ||
| 145 | const subkey_utf16le_len: usize = std.unicode.utf8ToUtf16Le(subkey_utf16le_buf[0..], subkey) catch unreachable; | ||
| 146 | subkey_utf16le_buf[subkey_utf16le_len] = 0; | ||
| 147 | break :subkey_utf16le subkey_utf16le_buf[0..subkey_utf16le_len :0]; | ||
| 148 | }; | ||
| 149 | |||
| 150 | const value_name_utf16le: [:0]const u16 = value_name_utf16le: { | ||
| 151 | var value_name_utf16le_buf: [RegistryUtf16Le.value_name_max_len]u16 = undefined; | ||
| 152 | const value_name_utf16le_len: usize = std.unicode.utf8ToUtf16Le(value_name_utf16le_buf[0..], value_name) catch unreachable; | ||
| 153 | value_name_utf16le_buf[value_name_utf16le_len] = 0; | ||
| 154 | break :value_name_utf16le value_name_utf16le_buf[0..value_name_utf16le_len :0]; | ||
| 155 | }; | ||
| 156 | |||
| 157 | const registry_utf16le = RegistryUtf16Le{ .key = self.key }; | ||
| 158 | return try registry_utf16le.getDword(subkey_utf16le, value_name_utf16le); | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Under private space with flags: | ||
| 162 | /// KEY_QUERY_VALUE and KEY_ENUMERATE_SUB_KEYS. | ||
| 163 | /// After finishing work, call `closeKey`. | ||
| 164 | pub fn loadFromPath(absolute_path: []const u8) error{KeyNotFound}!RegistryUtf8 { | ||
| 165 | const absolute_path_utf16le: [:0]const u16 = absolute_path_utf16le: { | ||
| 166 | var absolute_path_utf16le_buf: [RegistryUtf16Le.value_name_max_len]u16 = undefined; | ||
| 167 | const absolute_path_utf16le_len: usize = std.unicode.utf8ToUtf16Le(absolute_path_utf16le_buf[0..], absolute_path) catch unreachable; | ||
| 168 | absolute_path_utf16le_buf[absolute_path_utf16le_len] = 0; | ||
| 169 | break :absolute_path_utf16le absolute_path_utf16le_buf[0..absolute_path_utf16le_len :0]; | ||
| 170 | }; | ||
| 171 | |||
| 172 | const registry_utf16le = try RegistryUtf16Le.loadFromPath(absolute_path_utf16le); | ||
| 173 | return RegistryUtf8{ .key = registry_utf16le.key }; | ||
| 174 | } | ||
| 175 | }; | ||
| 176 | |||
| 177 | const RegistryUtf16Le = struct { | ||
| 178 | key: windows.HKEY, | ||
| 179 | |||
| 180 | /// Includes root key (f.e. HKEY_LOCAL_MACHINE). | ||
| 181 | /// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits | ||
| 182 | pub const key_name_max_len = 255; | ||
| 183 | /// In Unicode characters. | ||
| 184 | /// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits | ||
| 185 | pub const value_name_max_len = 16_383; | ||
| 186 | |||
| 187 | /// Under HKEY_LOCAL_MACHINE with flags: | ||
| 188 | /// KEY_QUERY_VALUE, KEY_WOW64_32KEY, and KEY_ENUMERATE_SUB_KEYS. | ||
| 189 | /// After finishing work, call `closeKey`. | ||
| 190 | fn openKey(key_utf16le: [:0]const u16) error{KeyNotFound}!RegistryUtf16Le { | ||
| 191 | var key: windows.HKEY = undefined; | ||
| 192 | const return_code_int: windows.HRESULT = windows.advapi32.RegOpenKeyExW( | ||
| 193 | windows.HKEY_LOCAL_MACHINE, | ||
| 194 | key_utf16le, | ||
| 195 | 0, | ||
| 196 | windows.KEY_QUERY_VALUE | windows.KEY_WOW64_32KEY | windows.KEY_ENUMERATE_SUB_KEYS, | ||
| 197 | &key, | ||
| 198 | ); | ||
| 199 | const return_code: windows.Win32Error = @enumFromInt(return_code_int); | ||
| 200 | switch (return_code) { | ||
| 201 | .SUCCESS => {}, | ||
| 202 | .FILE_NOT_FOUND => return error.KeyNotFound, | ||
| 203 | |||
| 204 | else => return error.KeyNotFound, | ||
| 205 | } | ||
| 206 | return RegistryUtf16Le{ .key = key }; | ||
| 207 | } | ||
| 208 | |||
| 209 | /// Closes key, after that usage is invalid | ||
| 210 | fn closeKey(self: *const RegistryUtf16Le) void { | ||
| 211 | const return_code_int: windows.HRESULT = windows.advapi32.RegCloseKey(self.key); | ||
| 212 | const return_code: windows.Win32Error = @enumFromInt(return_code_int); | ||
| 213 | switch (return_code) { | ||
| 214 | .SUCCESS => {}, | ||
| 215 | else => {}, | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | /// Get string ([:0]const u16) from registry. | ||
| 220 | fn getString(self: *const RegistryUtf16Le, allocator: std.mem.Allocator, subkey_utf16le: [:0]const u16, value_name_utf16le: [:0]const u16) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]const u16 { | ||
| 221 | var actual_type: windows.ULONG = undefined; | ||
| 222 | |||
| 223 | // Calculating length to allocate | ||
| 224 | var value_utf16le_buf_size: u32 = 0; // in bytes, including any terminating NUL character or characters. | ||
| 225 | var return_code_int: windows.HRESULT = windows.advapi32.RegGetValueW( | ||
| 226 | self.key, | ||
| 227 | subkey_utf16le, | ||
| 228 | value_name_utf16le, | ||
| 229 | RRF.RT_REG_SZ, | ||
| 230 | &actual_type, | ||
| 231 | null, | ||
| 232 | &value_utf16le_buf_size, | ||
| 233 | ); | ||
| 234 | |||
| 235 | // Check returned code and type | ||
| 236 | var return_code: windows.Win32Error = @enumFromInt(return_code_int); | ||
| 237 | switch (return_code) { | ||
| 238 | .SUCCESS => std.debug.assert(value_utf16le_buf_size != 0), | ||
| 239 | .MORE_DATA => unreachable, // We are only reading length | ||
| 240 | .FILE_NOT_FOUND => return error.ValueNameNotFound, | ||
| 241 | .INVALID_PARAMETER => unreachable, // We didn't combine RRF.SUBKEY_WOW6464KEY and RRF.SUBKEY_WOW6432KEY | ||
| 242 | else => return error.StringNotFound, | ||
| 243 | } | ||
| 244 | switch (actual_type) { | ||
| 245 | windows.REG.SZ => {}, | ||
| 246 | else => return error.NotAString, | ||
| 247 | } | ||
| 248 | |||
| 249 | var value_utf16le_buf: []u16 = try allocator.alloc(u16, std.math.divCeil(u32, value_utf16le_buf_size, 2) catch unreachable); | ||
| 250 | errdefer allocator.free(value_utf16le_buf); | ||
| 251 | |||
| 252 | return_code_int = windows.advapi32.RegGetValueW( | ||
| 253 | self.key, | ||
| 254 | subkey_utf16le, | ||
| 255 | value_name_utf16le, | ||
| 256 | RRF.RT_REG_SZ, | ||
| 257 | &actual_type, | ||
| 258 | value_utf16le_buf.ptr, | ||
| 259 | &value_utf16le_buf_size, | ||
| 260 | ); | ||
| 261 | |||
| 262 | // Check returned code and (just in case) type again. | ||
| 263 | return_code = @enumFromInt(return_code_int); | ||
| 264 | switch (return_code) { | ||
| 265 | .SUCCESS => {}, | ||
| 266 | .MORE_DATA => unreachable, // Calculated first time length should be enough, even overestimated | ||
| 267 | .FILE_NOT_FOUND => return error.ValueNameNotFound, | ||
| 268 | .INVALID_PARAMETER => unreachable, // We didn't combine RRF.SUBKEY_WOW6464KEY and RRF.SUBKEY_WOW6432KEY | ||
| 269 | else => return error.StringNotFound, | ||
| 270 | } | ||
| 271 | switch (actual_type) { | ||
| 272 | windows.REG.SZ => {}, | ||
| 273 | else => return error.NotAString, | ||
| 274 | } | ||
| 275 | |||
| 276 | const value_utf16le: []const u16 = value_utf16le: { | ||
| 277 | // note(bratishkaerik): somehow returned value in `buf_len` is overestimated by Windows and contains extra space | ||
| 278 | // we will just search for zero termination and forget length | ||
| 279 | // Windows sure is strange | ||
| 280 | const value_utf16le_overestimated: [*:0]const u16 = @ptrCast(value_utf16le_buf.ptr); | ||
| 281 | break :value_utf16le std.mem.span(value_utf16le_overestimated); | ||
| 282 | }; | ||
| 283 | |||
| 284 | _ = allocator.resize(value_utf16le_buf, value_utf16le.len); | ||
| 285 | return value_utf16le; | ||
| 286 | } | ||
| 287 | |||
| 288 | /// Get DWORD (u32) from registry. | ||
| 289 | fn getDword(self: *const RegistryUtf16Le, subkey_utf16le: [:0]const u16, value_name_utf16le: [:0]const u16) error{ ValueNameNotFound, NotADword, DwordTooLong, DwordNotFound }!u32 { | ||
| 290 | var actual_type: windows.ULONG = undefined; | ||
| 291 | var reg_size: u32 = @sizeOf(u32); | ||
| 292 | var reg_value: u32 = 0; | ||
| 293 | |||
| 294 | const return_code_int: windows.HRESULT = windows.advapi32.RegGetValueW( | ||
| 295 | self.key, | ||
| 296 | subkey_utf16le, | ||
| 297 | value_name_utf16le, | ||
| 298 | RRF.RT_REG_DWORD, | ||
| 299 | &actual_type, | ||
| 300 | &reg_value, | ||
| 301 | &reg_size, | ||
| 302 | ); | ||
| 303 | const return_code: windows.Win32Error = @enumFromInt(return_code_int); | ||
| 304 | switch (return_code) { | ||
| 305 | .SUCCESS => {}, | ||
| 306 | .MORE_DATA => return error.DwordTooLong, | ||
| 307 | .FILE_NOT_FOUND => return error.ValueNameNotFound, | ||
| 308 | .INVALID_PARAMETER => unreachable, // We didn't combine RRF.SUBKEY_WOW6464KEY and RRF.SUBKEY_WOW6432KEY | ||
| 309 | else => return error.DwordNotFound, | ||
| 310 | } | ||
| 311 | |||
| 312 | switch (actual_type) { | ||
| 313 | windows.REG.DWORD => {}, | ||
| 314 | else => return error.NotADword, | ||
| 315 | } | ||
| 316 | |||
| 317 | return reg_value; | ||
| 318 | } | ||
| 319 | |||
| 320 | /// Under private space with flags: | ||
| 321 | /// KEY_QUERY_VALUE and KEY_ENUMERATE_SUB_KEYS. | ||
| 322 | /// After finishing work, call `closeKey`. | ||
| 323 | fn loadFromPath(absolute_path_as_utf16le: [:0]const u16) error{KeyNotFound}!RegistryUtf16Le { | ||
| 324 | var key: windows.HKEY = undefined; | ||
| 325 | |||
| 326 | const return_code_int: windows.HRESULT = std.os.windows.advapi32.RegLoadAppKeyW( | ||
| 327 | absolute_path_as_utf16le, | ||
| 328 | &key, | ||
| 329 | windows.KEY_QUERY_VALUE | windows.KEY_ENUMERATE_SUB_KEYS, | ||
| 330 | 0, | ||
| 331 | 0, | ||
| 332 | ); | ||
| 333 | const return_code: windows.Win32Error = @enumFromInt(return_code_int); | ||
| 334 | switch (return_code) { | ||
| 335 | .SUCCESS => {}, | ||
| 336 | else => return error.KeyNotFound, | ||
| 337 | } | ||
| 338 | |||
| 339 | return RegistryUtf16Le{ .key = key }; | ||
| 340 | } | ||
| 341 | }; | ||
| 342 | |||
| 343 | pub const Windows10Sdk = struct { | ||
| 344 | path: []const u8, | ||
| 345 | version: []const u8, | ||
| 346 | |||
| 347 | /// Find path and version of Windows 10 SDK. | ||
| 348 | /// Caller owns the result's fields. | ||
| 349 | /// After finishing work, call `free(allocator)`. | ||
| 350 | fn find(allocator: std.mem.Allocator) error{ OutOfMemory, Windows10SdkNotFound, PathTooLong, VersionTooLong }!Windows10Sdk { | ||
| 351 | const v10_key = RegistryUtf8.openKey("SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0") catch |err| switch (err) { | ||
| 352 | error.KeyNotFound => return error.Windows10SdkNotFound, | ||
| 353 | }; | ||
| 354 | defer v10_key.closeKey(); | ||
| 355 | |||
| 356 | const path: []const u8 = path10: { | ||
| 357 | var path_maybe_with_trailing_slash = v10_key.getString(allocator, "", "InstallationFolder") catch |err| switch (err) { | ||
| 358 | error.NotAString => return error.Windows10SdkNotFound, | ||
| 359 | error.ValueNameNotFound => return error.Windows10SdkNotFound, | ||
| 360 | error.StringNotFound => return error.Windows10SdkNotFound, | ||
| 361 | |||
| 362 | error.OutOfMemory => return error.OutOfMemory, | ||
| 363 | }; | ||
| 364 | |||
| 365 | if (path_maybe_with_trailing_slash.len > std.fs.MAX_PATH_BYTES or !std.fs.path.isAbsolute(path_maybe_with_trailing_slash)) { | ||
| 366 | allocator.free(path_maybe_with_trailing_slash); | ||
| 367 | return error.PathTooLong; | ||
| 368 | } | ||
| 369 | |||
| 370 | var path = std.ArrayList(u8).fromOwnedSlice(allocator, path_maybe_with_trailing_slash); | ||
| 371 | errdefer path.deinit(); | ||
| 372 | |||
| 373 | // String might contain trailing slash, so trim it here | ||
| 374 | if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); | ||
| 375 | |||
| 376 | const path_without_trailing_slash = try path.toOwnedSlice(); | ||
| 377 | break :path10 path_without_trailing_slash; | ||
| 378 | }; | ||
| 379 | errdefer allocator.free(path); | ||
| 380 | |||
| 381 | const version: []const u8 = version10: { | ||
| 382 | |||
| 383 | // note(dimenus): Microsoft doesn't include the .0 in the ProductVersion key.... | ||
| 384 | var version_without_0 = v10_key.getString(allocator, "", "ProductVersion") catch |err| switch (err) { | ||
| 385 | error.NotAString => return error.Windows10SdkNotFound, | ||
| 386 | error.ValueNameNotFound => return error.Windows10SdkNotFound, | ||
| 387 | error.StringNotFound => return error.Windows10SdkNotFound, | ||
| 388 | |||
| 389 | error.OutOfMemory => return error.OutOfMemory, | ||
| 390 | }; | ||
| 391 | if (version_without_0.len + ".0".len > product_version_max_length) { | ||
| 392 | allocator.free(version_without_0); | ||
| 393 | return error.VersionTooLong; | ||
| 394 | } | ||
| 395 | |||
| 396 | var version = std.ArrayList(u8).fromOwnedSlice(allocator, version_without_0); | ||
| 397 | errdefer version.deinit(); | ||
| 398 | |||
| 399 | try version.appendSlice(".0"); | ||
| 400 | |||
| 401 | const version_with_0 = try version.toOwnedSlice(); | ||
| 402 | break :version10 version_with_0; | ||
| 403 | }; | ||
| 404 | errdefer allocator.free(version); | ||
| 405 | |||
| 406 | return Windows10Sdk{ .path = path, .version = version }; | ||
| 407 | } | ||
| 408 | |||
| 409 | /// Check whether this version is enumerated in registry. | ||
| 410 | fn isValidVersion(windows10sdk: *const Windows10Sdk) bool { | ||
| 411 | var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; | ||
| 412 | const reg_query_as_utf8 = std.fmt.bufPrint(buf[0..], "{s}\\{s}\\Installed Options", .{ WINDOWS_KIT_REG_KEY, windows10sdk.version }) catch |err| switch (err) { | ||
| 413 | error.NoSpaceLeft => return false, | ||
| 414 | }; | ||
| 415 | |||
| 416 | const options_key = RegistryUtf8.openKey(reg_query_as_utf8) catch |err| switch (err) { | ||
| 417 | error.KeyNotFound => return false, | ||
| 418 | }; | ||
| 419 | defer options_key.closeKey(); | ||
| 420 | |||
| 421 | const option_name = comptime switch (builtin.target.cpu.arch) { | ||
| 422 | .arm, .armeb => "OptionId.DesktopCPParm", | ||
| 423 | .aarch64 => "OptionId.DesktopCPParm64", | ||
| 424 | .x86_64 => "OptionId.DesktopCPPx64", | ||
| 425 | .x86 => "OptionId.DesktopCPPx86", | ||
| 426 | else => |tag| @compileError("Windows 10 SDK cannot be detected on architecture " ++ tag), | ||
| 427 | }; | ||
| 428 | |||
| 429 | const reg_value = options_key.getDword("", option_name) catch return false; | ||
| 430 | return (reg_value == 1); | ||
| 431 | } | ||
| 432 | |||
| 433 | fn free(self: *const Windows10Sdk, allocator: std.mem.Allocator) void { | ||
| 434 | allocator.free(self.path); | ||
| 435 | allocator.free(self.version); | ||
| 436 | } | ||
| 437 | }; | ||
| 438 | |||
| 439 | pub const Windows81Sdk = struct { | ||
| 440 | path: []const u8, | ||
| 441 | version: []const u8, | ||
| 442 | |||
| 443 | /// Find path and version of Windows 8.1 SDK. | ||
| 444 | /// Caller owns the result's fields. | ||
| 445 | /// After finishing work, call `free(allocator)`. | ||
| 446 | fn find(allocator: std.mem.Allocator, roots_key: *const RegistryUtf8) error{ OutOfMemory, Windows81SdkNotFound, PathTooLong, VersionTooLong }!Windows81Sdk { | ||
| 447 | const path: []const u8 = path81: { | ||
| 448 | var path_maybe_with_trailing_slash = roots_key.getString(allocator, "", "KitsRoot81") catch |err| switch (err) { | ||
| 449 | error.NotAString => return error.Windows81SdkNotFound, | ||
| 450 | error.ValueNameNotFound => return error.Windows81SdkNotFound, | ||
| 451 | error.StringNotFound => return error.Windows81SdkNotFound, | ||
| 452 | |||
| 453 | error.OutOfMemory => return error.OutOfMemory, | ||
| 454 | }; | ||
| 455 | if (path_maybe_with_trailing_slash.len > std.fs.MAX_PATH_BYTES or !std.fs.path.isAbsolute(path_maybe_with_trailing_slash)) { | ||
| 456 | allocator.free(path_maybe_with_trailing_slash); | ||
| 457 | return error.PathTooLong; | ||
| 458 | } | ||
| 459 | |||
| 460 | var path = std.ArrayList(u8).fromOwnedSlice(allocator, path_maybe_with_trailing_slash); | ||
| 461 | errdefer path.deinit(); | ||
| 462 | |||
| 463 | // String might contain trailing slash, so trim it here | ||
| 464 | if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); | ||
| 465 | |||
| 466 | const path_without_trailing_slash = try path.toOwnedSlice(); | ||
| 467 | break :path81 path_without_trailing_slash; | ||
| 468 | }; | ||
| 469 | errdefer allocator.free(path); | ||
| 470 | |||
| 471 | const version: []const u8 = version81: { | ||
| 472 | var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; | ||
| 473 | const sdk_lib_dir_path = std.fmt.bufPrint(buf[0..], "{s}\\Lib\\", .{path}) catch |err| switch (err) { | ||
| 474 | error.NoSpaceLeft => return error.PathTooLong, | ||
| 475 | }; | ||
| 476 | if (!std.fs.path.isAbsolute(sdk_lib_dir_path)) return error.Windows81SdkNotFound; | ||
| 477 | |||
| 478 | // enumerate files in sdk path looking for latest version | ||
| 479 | var sdk_lib_dir = std.fs.openIterableDirAbsolute(sdk_lib_dir_path, .{}) catch |err| switch (err) { | ||
| 480 | error.NameTooLong => return error.PathTooLong, | ||
| 481 | else => return error.Windows81SdkNotFound, | ||
| 482 | }; | ||
| 483 | defer sdk_lib_dir.close(); | ||
| 484 | |||
| 485 | var iterator = sdk_lib_dir.iterate(); | ||
| 486 | const versions = iterateAndFilterBySemVer(&iterator, allocator, "winv") catch |err| switch (err) { | ||
| 487 | error.OutOfMemory => return error.OutOfMemory, | ||
| 488 | error.VersionNotFound => return error.Windows81SdkNotFound, | ||
| 489 | }; | ||
| 490 | defer { | ||
| 491 | for (versions) |version| allocator.free(version); | ||
| 492 | allocator.free(versions); | ||
| 493 | } | ||
| 494 | const latest_version = try allocator.dupe(u8, versions[0]); | ||
| 495 | break :version81 latest_version; | ||
| 496 | }; | ||
| 497 | errdefer allocator.free(version); | ||
| 498 | |||
| 499 | return Windows81Sdk{ .path = path, .version = version }; | ||
| 500 | } | ||
| 501 | |||
| 502 | fn free(self: *const Windows81Sdk, allocator: std.mem.Allocator) void { | ||
| 503 | allocator.free(self.path); | ||
| 504 | allocator.free(self.version); | ||
| 505 | } | ||
| 506 | }; | ||
| 507 | |||
| 508 | pub const ZigWindowsSDK = struct { | ||
| 509 | windows10sdk: ?Windows10Sdk, | ||
| 510 | windows81sdk: ?Windows81Sdk, | ||
| 511 | msvc_lib_dir: ?[]const u8, | ||
| 512 | |||
| 513 | /// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory. | ||
| 514 | /// Caller owns the result's fields. | ||
| 515 | /// After finishing work, call `free(allocator)`. | ||
| 516 | pub fn find(allocator: std.mem.Allocator) error{ OutOfMemory, NotFound, PathTooLong }!ZigWindowsSDK { | ||
| 517 | if (builtin.os.tag != .windows) return error.NotFound; | ||
| 518 | |||
| 519 | //note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed | ||
| 520 | const roots_key = RegistryUtf8.openKey(WINDOWS_KIT_REG_KEY) catch |err| switch (err) { | ||
| 521 | error.KeyNotFound => return error.NotFound, | ||
| 522 | }; | ||
| 523 | defer roots_key.closeKey(); | ||
| 524 | |||
| 525 | const windows10sdk: ?Windows10Sdk = blk: { | ||
| 526 | const windows10sdk = Windows10Sdk.find(allocator) catch |err| switch (err) { | ||
| 527 | error.Windows10SdkNotFound, | ||
| 528 | error.PathTooLong, | ||
| 529 | error.VersionTooLong, | ||
| 530 | => break :blk null, | ||
| 531 | error.OutOfMemory => return error.OutOfMemory, | ||
| 532 | }; | ||
| 533 | const is_valid_version = windows10sdk.isValidVersion(); | ||
| 534 | if (!is_valid_version) break :blk null; | ||
| 535 | break :blk windows10sdk; | ||
| 536 | }; | ||
| 537 | errdefer if (windows10sdk) |*w| w.free(allocator); | ||
| 538 | |||
| 539 | const windows81sdk: ?Windows81Sdk = blk: { | ||
| 540 | const windows81sdk = Windows81Sdk.find(allocator, &roots_key) catch |err| switch (err) { | ||
| 541 | error.Windows81SdkNotFound => break :blk null, | ||
| 542 | error.PathTooLong => break :blk null, | ||
| 543 | error.VersionTooLong => break :blk null, | ||
| 544 | error.OutOfMemory => return error.OutOfMemory, | ||
| 545 | }; | ||
| 546 | // no check | ||
| 547 | break :blk windows81sdk; | ||
| 548 | }; | ||
| 549 | errdefer if (windows81sdk) |*w| w.free(allocator); | ||
| 550 | |||
| 551 | const msvc_lib_dir: ?[]const u8 = MsvcLibDir.find(allocator) catch |err| switch (err) { | ||
| 552 | error.MsvcLibDirNotFound => null, | ||
| 553 | error.PathTooLong => null, | ||
| 554 | error.OutOfMemory => return error.OutOfMemory, | ||
| 555 | }; | ||
| 556 | errdefer allocator.free(msvc_lib_dir); | ||
| 557 | |||
| 558 | return ZigWindowsSDK{ | ||
| 559 | .windows10sdk = windows10sdk, | ||
| 560 | .windows81sdk = windows81sdk, | ||
| 561 | .msvc_lib_dir = msvc_lib_dir, | ||
| 562 | }; | ||
| 563 | } | ||
| 564 | |||
| 565 | pub fn free(self: *const ZigWindowsSDK, allocator: std.mem.Allocator) void { | ||
| 566 | if (self.windows10sdk) |*w10sdk| { | ||
| 567 | w10sdk.free(allocator); | ||
| 568 | } | ||
| 569 | if (self.windows81sdk) |*w81sdk| { | ||
| 570 | w81sdk.free(allocator); | ||
| 571 | } | ||
| 572 | if (self.msvc_lib_dir) |msvc_lib_dir| { | ||
| 573 | allocator.free(msvc_lib_dir); | ||
| 574 | } | ||
| 575 | } | ||
| 576 | }; | ||
| 577 | |||
| 578 | const MsvcLibDir = struct { | ||
| 579 | // https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances?view=vs-2022#editing-the-registry-for-a-visual-studio-instance | ||
| 580 | fn findViaRegistry(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }![]const u8 { | ||
| 581 | |||
| 582 | // %localappdata%\Microsoft\VisualStudio\ | ||
| 583 | // %appdata%\Local\Microsoft\VisualStudio\ | ||
| 584 | const visualstudio_folder_path = std.fs.getAppDataDir(allocator, "Microsoft\\VisualStudio\\") catch return error.PathNotFound; | ||
| 585 | defer allocator.free(visualstudio_folder_path); | ||
| 586 | |||
| 587 | const vs_versions: []const []const u8 = vs_versions: { | ||
| 588 | if (!std.fs.path.isAbsolute(visualstudio_folder_path)) return error.PathNotFound; | ||
| 589 | // enumerate folders that contain `privateregistry.bin`, looking for all versions | ||
| 590 | // f.i. %localappdata%\Microsoft\VisualStudio\17.0_9e9cbb98\ | ||
| 591 | var visualstudio_folder = std.fs.openIterableDirAbsolute(visualstudio_folder_path, .{}) catch return error.PathNotFound; | ||
| 592 | defer visualstudio_folder.close(); | ||
| 593 | |||
| 594 | var iterator = visualstudio_folder.iterate(); | ||
| 595 | const versions = iterateAndFilterBySemVer(&iterator, allocator, null) catch |err| switch (err) { | ||
| 596 | error.OutOfMemory => return error.OutOfMemory, | ||
| 597 | error.VersionNotFound => return error.PathNotFound, | ||
| 598 | }; | ||
| 599 | break :vs_versions versions; | ||
| 600 | }; | ||
| 601 | defer { | ||
| 602 | for (vs_versions) |vs_version| allocator.free(vs_version); | ||
| 603 | allocator.free(vs_versions); | ||
| 604 | } | ||
| 605 | var config_subkey_buf: [RegistryUtf16Le.key_name_max_len * 2]u8 = undefined; | ||
| 606 | const source_directories: []const u8 = source_directories: for (vs_versions) |vs_version| { | ||
| 607 | const privateregistry_absolute_path = std.fs.path.join(allocator, &.{ visualstudio_folder_path, vs_version, "privateregistry.bin" }) catch continue; | ||
| 608 | defer allocator.free(privateregistry_absolute_path); | ||
| 609 | if (!std.fs.path.isAbsolute(privateregistry_absolute_path)) continue; | ||
| 610 | |||
| 611 | const visualstudio_registry = RegistryUtf8.loadFromPath(privateregistry_absolute_path) catch continue; | ||
| 612 | defer visualstudio_registry.closeKey(); | ||
| 613 | |||
| 614 | const config_subkey = std.fmt.bufPrint(config_subkey_buf[0..], "Software\\Microsoft\\VisualStudio\\{s}_Config", .{vs_version}) catch unreachable; | ||
| 615 | |||
| 616 | var source_directories_value = visualstudio_registry.getString(allocator, config_subkey, "Source Directories") catch |err| switch (err) { | ||
| 617 | error.OutOfMemory => return error.OutOfMemory, | ||
| 618 | else => continue, | ||
| 619 | }; | ||
| 620 | if (source_directories_value.len > (std.fs.MAX_PATH_BYTES * 30)) { // note(bratishkaerik): guessing from the fact that on my computer it has 15 pathes and at least some of them are not of max length | ||
| 621 | allocator.free(source_directories_value); | ||
| 622 | continue; | ||
| 623 | } | ||
| 624 | |||
| 625 | break :source_directories source_directories_value; | ||
| 626 | } else return error.PathNotFound; | ||
| 627 | defer allocator.free(source_directories); | ||
| 628 | |||
| 629 | var source_directories_splitted = std.mem.splitScalar(u8, source_directories, ';'); | ||
| 630 | |||
| 631 | const msvc_dir: []const u8 = msvc_dir: { | ||
| 632 | var msvc_include_dir_maybe_with_trailing_slash = try allocator.dupe(u8, source_directories_splitted.first()); | ||
| 633 | |||
| 634 | if (msvc_include_dir_maybe_with_trailing_slash.len > std.fs.MAX_PATH_BYTES or !std.fs.path.isAbsolute(msvc_include_dir_maybe_with_trailing_slash)) { | ||
| 635 | allocator.free(msvc_include_dir_maybe_with_trailing_slash); | ||
| 636 | return error.PathNotFound; | ||
| 637 | } | ||
| 638 | |||
| 639 | var msvc_dir = std.ArrayList(u8).fromOwnedSlice(allocator, msvc_include_dir_maybe_with_trailing_slash); | ||
| 640 | errdefer msvc_dir.deinit(); | ||
| 641 | |||
| 642 | // String might contain trailing slash, so trim it here | ||
| 643 | if (msvc_dir.items.len > "C:\\".len and msvc_dir.getLast() == '\\') _ = msvc_dir.pop(); | ||
| 644 | |||
| 645 | // Remove `\include` at the end of path | ||
| 646 | if (std.mem.endsWith(u8, msvc_dir.items, "\\include")) { | ||
| 647 | msvc_dir.shrinkRetainingCapacity(msvc_dir.items.len - "\\include".len); | ||
| 648 | } | ||
| 649 | |||
| 650 | const folder_with_arch = "\\Lib\\" ++ comptime switch (builtin.target.cpu.arch) { | ||
| 651 | .x86 => "x86", | ||
| 652 | .x86_64 => "x64", | ||
| 653 | .arm, .armeb => "arm", | ||
| 654 | .aarch64 => "arm64", | ||
| 655 | else => |tag| @compileError("MSVC lib dir cannot be detected on architecture " ++ tag), | ||
| 656 | }; | ||
| 657 | |||
| 658 | try msvc_dir.appendSlice(folder_with_arch); | ||
| 659 | const msvc_dir_with_arch = try msvc_dir.toOwnedSlice(); | ||
| 660 | break :msvc_dir msvc_dir_with_arch; | ||
| 661 | }; | ||
| 662 | errdefer allocator.free(msvc_dir); | ||
| 663 | |||
| 664 | return msvc_dir; | ||
| 665 | } | ||
| 666 | |||
| 667 | fn findViaVs7Key(allocator: std.mem.Allocator) error{ OutOfMemory, PathNotFound }![]const u8 { | ||
| 668 | var base_path: std.ArrayList(u8) = base_path: { | ||
| 669 | try_env: { | ||
| 670 | var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) { | ||
| 671 | error.OutOfMemory => return error.OutOfMemory, | ||
| 672 | else => break :try_env, | ||
| 673 | }; | ||
| 674 | defer env_map.deinit(); | ||
| 675 | |||
| 676 | if (env_map.get("VS140COMNTOOLS")) |VS140COMNTOOLS| { | ||
| 677 | if (VS140COMNTOOLS.len < "C:\\Common7\\Tools".len) break :try_env; | ||
| 678 | if (!std.fs.path.isAbsolute(VS140COMNTOOLS)) break :try_env; | ||
| 679 | var list = std.ArrayList(u8).init(allocator); | ||
| 680 | errdefer list.deinit(); | ||
| 681 | |||
| 682 | try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools | ||
| 683 | // String might contain trailing slash, so trim it here | ||
| 684 | if (list.items.len > "C:\\".len and list.getLast() == '\\') _ = list.pop(); | ||
| 685 | list.shrinkRetainingCapacity(list.items.len - "\\Common7\\Tools".len); // C:\Program Files (x86)\Microsoft Visual Studio 14.0 | ||
| 686 | break :base_path list; | ||
| 687 | } | ||
| 688 | } | ||
| 689 | |||
| 690 | const vs7_key = RegistryUtf8.openKey("SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7") catch return error.PathNotFound; | ||
| 691 | defer vs7_key.closeKey(); | ||
| 692 | try_vs7_key: { | ||
| 693 | var path_maybe_with_trailing_slash = vs7_key.getString(allocator, "", "14.0") catch |err| switch (err) { | ||
| 694 | error.OutOfMemory => return error.OutOfMemory, | ||
| 695 | else => break :try_vs7_key, | ||
| 696 | }; | ||
| 697 | |||
| 698 | if (path_maybe_with_trailing_slash.len > std.fs.MAX_PATH_BYTES or !std.fs.path.isAbsolute(path_maybe_with_trailing_slash)) { | ||
| 699 | allocator.free(path_maybe_with_trailing_slash); | ||
| 700 | break :try_vs7_key; | ||
| 701 | } | ||
| 702 | |||
| 703 | var path = std.ArrayList(u8).fromOwnedSlice(allocator, path_maybe_with_trailing_slash); | ||
| 704 | errdefer path.deinit(); | ||
| 705 | |||
| 706 | // String might contain trailing slash, so trim it here | ||
| 707 | if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); | ||
| 708 | break :base_path path; | ||
| 709 | } | ||
| 710 | return error.PathNotFound; | ||
| 711 | }; | ||
| 712 | errdefer base_path.deinit(); | ||
| 713 | |||
| 714 | const folder_with_arch = "\\VC\\lib\\" ++ comptime switch (builtin.target.cpu.arch) { | ||
| 715 | .x86 => "", //x86 is in the root of the Lib folder | ||
| 716 | .x86_64 => "amd64", | ||
| 717 | .arm, .armeb => "arm", | ||
| 718 | .aarch64 => "arm64", | ||
| 719 | else => |tag| @compileError("MSVC lib dir cannot be detected on architecture " ++ tag), | ||
| 720 | }; | ||
| 721 | try base_path.appendSlice(folder_with_arch); | ||
| 722 | |||
| 723 | const full_path = try base_path.toOwnedSlice(); | ||
| 724 | return full_path; | ||
| 725 | } | ||
| 726 | |||
| 727 | /// Find path to MSVC's `lib/` directory. | ||
| 728 | /// Caller owns the result. | ||
| 729 | pub fn find(allocator: std.mem.Allocator) error{ OutOfMemory, MsvcLibDirNotFound, PathTooLong }![]const u8 { | ||
| 730 | const full_path = MsvcLibDir.findViaRegistry(allocator) catch |err1| switch (err1) { | ||
| 731 | error.OutOfMemory => return error.OutOfMemory, | ||
| 732 | error.PathNotFound => MsvcLibDir.findViaVs7Key(allocator) catch |err2| switch (err2) { | ||
| 733 | error.OutOfMemory => return error.OutOfMemory, | ||
| 734 | error.PathNotFound => return error.MsvcLibDirNotFound, | ||
| 735 | }, | ||
| 736 | }; | ||
| 737 | errdefer allocator.free(full_path); | ||
| 738 | std.debug.assert(std.fs.path.isAbsolute(full_path)); // should be already handled in `findVia*` | ||
| 739 | |||
| 740 | var dir = std.fs.openDirAbsolute(full_path, .{}) catch |err| switch (err) { | ||
| 741 | error.NameTooLong => return error.PathTooLong, | ||
| 742 | else => return error.MsvcLibDirNotFound, | ||
| 743 | }; | ||
| 744 | defer dir.close(); | ||
| 745 | |||
| 746 | const stat = dir.statFile("vcruntime.lib") catch |err| switch (err) { | ||
| 747 | error.NameTooLong => return error.PathTooLong, | ||
| 748 | else => return error.MsvcLibDirNotFound, | ||
| 749 | }; | ||
| 750 | if (stat.kind != .file) | ||
| 751 | return error.MsvcLibDirNotFound; | ||
| 752 | |||
| 753 | return full_path; | ||
| 754 | } | ||
| 27 | }; | 755 | }; |