1 /****************************************************************************** 2 * Copyright (c) 2016 The Khronos Group 3 * Copyright (c) 2016 Valve Corporation 4 * Copyright (c) 2016 LunarG, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you man not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is destributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language govering permissions and 16 * limitations under the License. 17 * 18 * Author: Lenny Komow <lenny (at) lunarg.com> 19 * 20 *****************************************************************************/ 21 22 /* 23 * This program is used by the Vulkan Runtime Installer/Uninstaller to: 24 * - Copy the most recent vulkan<majorabi>-*.dll in C:\Windows\System32 25 * to vulkan<majorabi>.dll 26 * - Copy the most recent version of vulkaninfo-<abimajor>-*.exe in 27 * C:\Windows\System32 to vulkaninfo.exe 28 * - The same thing is done for those files in C:\Windows\SysWOW64, but 29 * only on a 64-bit target 30 * - Set the layer registry entried to point to the layer json files in 31 * the Vulkan SDK associated with the most recent vulkan*.dll 32 * 33 * The program must be called with the following parameters: 34 * --major-abi: A single number specifying the major abi version 35 */ 36 37 // Compile with: `cl.exe configure_runtime.c /link advapi32.lib` 38 // Be sure to use the x86 version of cl.exe 39 40 #include <stdbool.h> 41 #include <stdint.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <windows.h> 46 47 // This hack gets Visual Studio 2013 to handle C99 stuff properly 48 // If we drop support for 2013, it would be a good idea to remove this 49 #if _MSC_VER < 1900 50 #define inline __inline 51 #define snprintf _snprintf 52 #endif 53 54 #if defined(_WIN64) 55 #error "This program is designed only as a 32-bit program. It should not be built as 64-bit." 56 #endif 57 58 #define COPY_BUFFER_SIZE (1024) 59 #define CHECK_ERROR(statement) { int error = (statement); if(error) return error; } 60 #define CHECK_ERROR_HANDLED(statement, handler) { int error = (statement); if(error) { { handler } return error; } } 61 #define SDK_VERSION_BUFFER_SIZE (64) 62 63 enum Platform 64 { 65 PLATFORM_X64, 66 PLATFORM_X86, 67 }; 68 69 #pragma pack(1) 70 struct SDKVersion 71 { 72 long major; 73 long minor; 74 long patch; 75 long build; 76 char extended[SDK_VERSION_BUFFER_SIZE]; 77 }; 78 79 const char* FLAG_ABI_MAJOR = "--abi-major"; 80 const char* PATH_SYSTEM32 = "\\SYSTEM32\\"; 81 const char* PATH_SYSWOW64 = "\\SysWOW64\\"; 82 83 inline size_t max_s(size_t a, size_t b) { return a > b ? a : b; } 84 inline size_t min_s(size_t a, size_t b) { return a > b ? a : b; } 85 86 // Add the registry entries for all explicit layers 87 // 88 // log (input) - Logging file stream 89 // install_path (input) - The installation path of the SDK which provides the layers 90 // platform (input) - The platform to set the installation for (x64 or x86) 91 // Returns: Zero on success, an error code on failure 92 int add_explicit_layers(FILE* log, const char* install_path, enum Platform platform); 93 94 // Compare two sdk versions 95 // 96 // Returns: Zero if they are equal, below zero if a predates b, greater than zero if b predates a 97 int compare_versions(const struct SDKVersion* a, const struct SDKVersion* b); 98 99 // Locate all of the SDK installations 100 // 101 // install_paths (output) - A poiner to an array of the installations paths 102 // install_versions (output) - A pointer to an array of the SDK versions 103 // count (output) - A pointer to the number of items in each array 104 // Returns: Zero on success, an error code on failure 105 // 106 // Both install_paths and install_versions are allocated on the heap. To free them properly, 107 // call free_installations(), even if this function returned an error code. The orders of 108 // install_paths and install_versions match, so (*install_paths)[2] is guaranteed to match 109 // (*install_versions)[2] 110 int find_installations(char*** install_paths, struct SDKVersion** install_versions, size_t* count); 111 112 // Free the memory allocated by find_installations() 113 void free_installations(char** install_paths, struct SDKVersion* install_versions, size_t count); 114 115 // Parse command line arguments for the program 116 // 117 // log (input) - Logging file stream 118 // argc (input) - The argument count 119 // argv (input) - An array of argument strings 120 // abi_major (output) - The major abi version from the arguments 121 // Returns: Zero on success, an error code on failure 122 int parse_arguments(FILE* log, int argc, char** argv, long* abi_major); 123 124 // Read the version from a string 125 // 126 // version_string (input) - A string in the format <abi>.<major>.<minor>.<patch>.<build>.<extended> 127 // version (output) - The version indicated by the input string 128 // Returns: Zero on success, an error code on failure 129 int read_version(const char* version_string, struct SDKVersion* version); 130 131 // Read the version from a filename 132 // 133 // filename (input) - The name of a .dll or .exe file, in the format 134 // somename-<abi>-<major>-<minor>-<path>-<build>-<extended>.dll 135 // version (output) - The versions indicated by the input string 136 // Returns: Zero on success, an error code on failure 137 int read_version_from_filename(const char* filename, struct SDKVersion* version); 138 139 // Remove explicit layers from the Windows registry 140 // 141 // log (input) - Loggin file stream 142 // install_paths (input) - An array of every vulkan installation path 143 // count (input) - The number of vulkan installations 144 // platform (input) - The platform (x64 or x86) of the registry to use (both exist on x64) 145 // Returns: Zero on success, an error code on failure 146 int remove_explicit_layers(FILE* log, const char** install_paths, size_t count, enum Platform platform); 147 148 // Update all explicity layers in the windows registry 149 // 150 // log (input) - Logging file stream 151 // platform (input) - The platform of the OS (both registries will be modified if this is x64) 152 // version (input) - The version that should be set to current (if it exists) 153 // Returns: Zero on success, an error code on failure 154 int update_registry_layers(FILE* log, enum Platform platform, const struct SDKVersion* version); 155 156 // Update a single vulkan system file (vulkan.dll or vulkaninfo.exe) 157 // 158 // log (input) - Loggin file stream 159 // name (input) - The name (excuding file extension) of the file to be updated 160 // extension (input) - The file extensions of the file to be updated 161 // path (input) - The directory of the file (usually System32 or SysWOW64) 162 // abi_major (input) - The ABI major version to be updated 163 // append_abi_major (input) - Whether or not the ABI number should be appended to the filename 164 // latest_version (output) - The version of the runtime which the file was updated to 165 // Returns: Zero on success, an error code on failure 166 int update_system_file(FILE* log, const char* name, const char* extension, const char* path, 167 long abi_major, bool append_abi_major, struct SDKVersion* latest_version); 168 169 // Update vulkan.dll and vulkaninfo.exe in all of the windows directories (System32 and SysWOW64) 170 // 171 // log (input) - Loging file stream 172 // abi_major (input) - The ABI major version of the files that should be used 173 // platform (input) - The platform for the current OS 174 // latest_runtime_version (output) - The version that the runtime files were updated to 175 int update_windows_directories(FILE* log, long abi_major, enum Platform platform, 176 struct SDKVersion* latest_runtime_version); 177 178 int main(int argc, char** argv) 179 { 180 // Get the OS platform (x86 or x64) 181 BOOL is_64_bit; 182 IsWow64Process(GetCurrentProcess(), &is_64_bit); 183 enum Platform platform = is_64_bit ? PLATFORM_X64 : PLATFORM_X86; 184 185 FILE* log = fopen("configure_rt.log", "w"); 186 if(log == NULL) { 187 return 10; 188 } 189 190 // Parse the arguments to get the abi version and the number of bits of the OS 191 long abi_major; 192 CHECK_ERROR_HANDLED(parse_arguments(log, argc, argv, &abi_major), { fclose(log); }); 193 194 // This makes System32 and SysWOW64 not do any redirection (well, until 128-bit is a thing) 195 Wow64DisableWow64FsRedirection(NULL); 196 197 // Update System32 (on all systems) and SysWOW64 on 64-bit system 198 struct SDKVersion latest_runtime_version; 199 CHECK_ERROR_HANDLED(update_windows_directories(log, abi_major, platform, &latest_runtime_version), 200 { fclose(log); }); 201 202 // Update the explicit layers that are set in the windows registry 203 CHECK_ERROR_HANDLED(update_registry_layers(log, platform, &latest_runtime_version), { fclose(log); }); 204 205 fclose(log); 206 return 0; 207 } 208 209 int add_explicit_layers(FILE* log, const char* install_path, enum Platform platform) 210 { 211 switch(platform) 212 { 213 case PLATFORM_X64: 214 fprintf(log, "Updating x64 explicit layers to path: %s\n", install_path); 215 break; 216 case PLATFORM_X86: 217 fprintf(log, "Updating x86 explicit layers to path: %s\n", install_path); 218 break; 219 } 220 221 // If this is a 32 bit system, we allow redirection to point this at the 32-bit registries. 222 // If not, we add the flag KEY_WOW64_64KEY, to disable redirection for this node. 223 HKEY hKey; 224 REGSAM flags = KEY_ALL_ACCESS; 225 if(platform == PLATFORM_X64) { 226 flags |= KEY_WOW64_64KEY; 227 } 228 229 // Create (if needed) and open the explicit layer key 230 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers", 231 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &hKey, NULL) != ERROR_SUCCESS) { 232 return 20; 233 } 234 235 const char* pattern = platform == PLATFORM_X64 ? "%s\\Bin\\VkLayer*.json" : "%s\\Bin32\\VkLayer*.json"; 236 int filter_size = snprintf(NULL, 0, pattern, install_path) + 1; 237 if(filter_size < 0) { 238 return 30; 239 } 240 char* filter = malloc(filter_size); 241 snprintf(filter, filter_size, pattern, install_path); 242 243 WIN32_FIND_DATA find_data; 244 HANDLE find = FindFirstFile(filter, &find_data); 245 free(filter); 246 for(bool at_end = (find != INVALID_HANDLE_VALUE); at_end; 247 at_end = FindNextFile(find, &find_data)) { 248 249 const char* layer_pattern = platform == PLATFORM_X64 ? "%s\\Bin\\%s" : "%s\\Bin32\\%s"; 250 int layer_size = snprintf(NULL, 0, layer_pattern, install_path, find_data.cFileName) + 1; 251 if(layer_size < 0) { 252 return 40; 253 } 254 char* layer = malloc(layer_size); 255 snprintf(layer, layer_size, layer_pattern, install_path, find_data.cFileName); 256 257 fprintf(log, "Adding explicit layer: %s\n", layer); 258 259 DWORD zero = 0; 260 LSTATUS err = RegSetValueEx(hKey, layer, zero, REG_DWORD, (BYTE*) &zero, sizeof(DWORD)); 261 free(layer); 262 if(err != ERROR_SUCCESS) { 263 return 50; 264 } 265 } 266 267 RegCloseKey(hKey); 268 return 0; 269 } 270 271 int compare_versions(const struct SDKVersion* a, const struct SDKVersion* b) 272 { 273 // Compare numerical versions 274 for(int i = 0; i < 4; ++i) { 275 long* a_current = ((long*) a) + i; 276 long* b_current = ((long*) b) + i; 277 278 if(*a_current < *b_current) { 279 return -4 + i; 280 } else if(*b_current < *a_current) { 281 return 4 - i; 282 } 283 } 284 285 // An empty string should be considered greater (and therefore more recent) than one with test 286 if(a->extended[0] == '\0' && b->extended[0] != '\0') { 287 return 1; 288 } else if(b->extended[0] == '\0' && a->extended[0] != '\0') { 289 return -1; 290 } 291 292 // Otherwise, just do a strncmp 293 return strncmp(a->extended, b->extended, SDK_VERSION_BUFFER_SIZE); 294 } 295 296 int find_installations(char*** install_paths, struct SDKVersion** install_versions, size_t* count) 297 { 298 *install_paths = malloc(sizeof(char*) * 64); 299 *install_versions = malloc(sizeof(struct SDKVersion) * 64); 300 *count = 0; 301 302 // We want the 64-bit registries on 64-bit windows, and the 32-bit registries on 32-bit Windows. 303 // KEY_WOW64_64KEY accomplishes this because it gets ignored on 32-bit Windows. 304 HKEY hKey; 305 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 306 0, KEY_READ | KEY_WOW64_64KEY, &hKey) != ERROR_SUCCESS) { 307 return 90; 308 } 309 310 DWORD keyCount, keyLen; 311 RegQueryInfoKey(hKey, NULL, NULL, NULL, &keyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 312 for(int i = 0; i < keyCount; ++i) { 313 TCHAR name[COPY_BUFFER_SIZE]; 314 DWORD nameSize = COPY_BUFFER_SIZE; 315 RegEnumKeyEx(hKey, i, name, &nameSize, NULL, NULL, NULL, NULL); 316 317 if(strncmp("VulkanSDK", name, 9)) { 318 continue; 319 } 320 321 HKEY subKey; 322 if(RegOpenKeyEx(hKey, name, 0, KEY_READ | KEY_WOW64_64KEY, &subKey) != ERROR_SUCCESS) { 323 continue; 324 } 325 326 bool found_installation = false, found_version = false; 327 DWORD valueCount; 328 RegQueryInfoKey(subKey, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, NULL, NULL, NULL, NULL); 329 for(int j = 0; j < valueCount; ++j) { 330 331 TCHAR name[COPY_BUFFER_SIZE], value[COPY_BUFFER_SIZE]; 332 DWORD type, buffSize = COPY_BUFFER_SIZE; 333 RegEnumValue(subKey, j, name, &buffSize, NULL, &type, value, &buffSize); 334 if(type == REG_SZ && !strcmp("InstallDir", name)) { 335 *install_paths = realloc(*install_paths, sizeof(char*) * ((*count) + 1)); 336 (*install_paths)[*count] = malloc(sizeof(char) * COPY_BUFFER_SIZE); 337 strcpy((*install_paths)[*count], value); 338 found_installation = true; 339 } else if(type == REG_SZ && !strncmp("DisplayVersion", name, 8)) { 340 *install_versions = realloc(*install_versions, sizeof(struct SDKVersion) * ((*count) + 1)); 341 CHECK_ERROR(read_version(value, (*install_versions) + *count)); 342 found_version = true; 343 } 344 345 if(found_installation && found_version) { 346 ++(*count); 347 break; 348 } 349 } 350 RegCloseKey(subKey); 351 352 if(!(found_installation && found_version)) { 353 RegCloseKey(hKey); 354 return 100; 355 } 356 } 357 RegCloseKey(hKey); 358 359 return 0; 360 } 361 362 void free_installations(char** install_paths, struct SDKVersion* install_versions, size_t count) 363 { 364 for(size_t i = 0; i < count; ++i) { 365 free(install_paths[i]); 366 } 367 free(install_paths); 368 free(install_versions); 369 } 370 371 int parse_arguments(FILE* log, int argc, char** argv, long* abi_major) 372 { 373 *abi_major = 0; 374 375 // Parse arguments 376 for(int i = 0; i < argc; ++i) { 377 if(!strcmp(argv[i], FLAG_ABI_MAJOR)) { 378 if(i + 1 == argc) { 379 fprintf(log, "ERROR: No value given for flag %s.\n", FLAG_ABI_MAJOR); 380 return 110; 381 } 382 *abi_major = strtol(argv[++i], NULL, 10); 383 if(*abi_major == 0) { 384 fprintf(log, "ERROR: Unable to parse ABI major version as integer.\n"); 385 return 120; 386 } 387 } 388 } 389 390 // Check that we have everything we need 391 if(*abi_major == 0 ) { 392 fprintf(log, "ERROR: Flag %s must be provided.\n", FLAG_ABI_MAJOR); 393 return 130; 394 } 395 396 // It all worked fine 397 fprintf(log, "Found ABI: %ld\n\n", *abi_major); 398 return 0; 399 } 400 401 int read_version(const char* version_string, struct SDKVersion* version) 402 { 403 size_t borders[4], dot_count = 0, i; 404 for(i = 0; dot_count < 3 && version_string[i] != '\0'; ++i) { 405 if(version_string[i] == '.') { 406 borders[dot_count++] = i + 1; 407 } 408 } 409 borders[3] = i + 1; 410 411 if(dot_count < 3) { 412 return 140; 413 } 414 415 // Read the version number 416 version->major = strtol(version_string, NULL, 10); 417 version->minor = strtol(version_string + borders[0], NULL, 10); 418 version->patch = strtol(version_string + borders[1], NULL, 10); 419 version->build = strtol(version_string + borders[2], NULL, 10); 420 421 strncpy(version->extended, version_string + borders[3] + 1, 422 min_s(SDK_VERSION_BUFFER_SIZE - 1, strlen(version_string + borders[3] + 1))); 423 424 return 0; 425 } 426 427 int read_version_from_filename(const char* filename, struct SDKVersion* version) 428 { 429 size_t borders[5], dash_count = 0; 430 431 // Locate all of the dashes that divides different version numbers 432 size_t i; 433 for(i = 0; dash_count < 5; ++i) { 434 if(filename[i] == '-' && dash_count == 0) { 435 ++dash_count; 436 } else if(filename[i] == '-') { 437 borders[dash_count++ - 1] = i + 1; 438 } else if(filename[i] == '\0') { 439 return 150; 440 } 441 } 442 borders[4] = i + 1; 443 444 // Read the version number 445 version->major = strtol(filename + borders[0], NULL, 10); 446 version->minor = strtol(filename + borders[1], NULL, 10); 447 version->patch = strtol(filename + borders[2], NULL, 10); 448 version->build = strtol(filename + borders[3], NULL, 10); 449 450 if(strcmp(filename + borders[4] + 1, "dll") && strcmp(filename + borders[4] + 1, "exe")) { 451 strncpy(version->extended, filename + borders[4] + 1, SDK_VERSION_BUFFER_SIZE - 1); 452 size_t file_len = strlen(filename + borders[4] + 1); 453 if(file_len - 4 < SDK_VERSION_BUFFER_SIZE) { 454 version->extended[file_len - 4] = '\0'; 455 } 456 } else { 457 version->extended[0] = '\0'; 458 } 459 460 for(size_t i = 0; version->extended[i] != '\0' && i < SDK_VERSION_BUFFER_SIZE; ++i) { 461 if(version->extended[i] == '-') { 462 version->extended[i] = '.'; 463 } 464 } 465 466 return 0; 467 } 468 469 int remove_explicit_layers(FILE* log, const char** install_paths, size_t count, enum Platform platform) 470 { 471 switch(platform) 472 { 473 case PLATFORM_X64: 474 fprintf(log, "Removing x64 explicit layers from registry\n"); 475 break; 476 case PLATFORM_X86: 477 fprintf(log, "Removing x86 explicit layers from registry\n"); 478 break; 479 } 480 481 bool removed_one; 482 do { 483 // If this is a 32 bit system, we allow redirection to point this at the 32-bit registries. 484 // If not, we add the flag KEY_WOW64_64KEY, to disable redirection for this node. 485 HKEY hKey; 486 REGSAM flags = KEY_ALL_ACCESS; 487 if(platform == PLATFORM_X64) { 488 flags |= KEY_WOW64_64KEY; 489 } 490 491 // Create (if needed) and open the explicit layer key 492 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers", 493 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &hKey, NULL) != ERROR_SUCCESS) { 494 return 160; 495 } 496 497 removed_one = false; 498 DWORD valueCount; 499 RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, NULL, NULL, NULL, NULL); 500 for(DWORD i = 0; i < valueCount; ++i) { 501 TCHAR name[COPY_BUFFER_SIZE]; 502 DWORD type, buffSize = COPY_BUFFER_SIZE; 503 RegEnumValue(hKey, i, name, &buffSize, NULL, &type, NULL, NULL); 504 505 for(size_t j = 0; j < count; ++j) { 506 if(strncmp(install_paths[j], name, strlen(install_paths[j])) == 0) { 507 fprintf(log, "Removing explicit layer entry: %s\n", name); 508 LSTATUS err = RegDeleteValue(hKey, name); 509 if(err != ERROR_SUCCESS) { 510 return 170; 511 } 512 removed_one = true; 513 break; 514 } 515 } 516 if(removed_one) { 517 break; 518 } 519 } 520 521 RegCloseKey(hKey); 522 } while(removed_one); 523 524 return 0; 525 } 526 527 int update_registry_layers(FILE* log, enum Platform platform, const struct SDKVersion* version) 528 { 529 char** install_paths; 530 struct SDKVersion* install_versions; 531 size_t count; 532 CHECK_ERROR_HANDLED(find_installations(&install_paths, &install_versions, &count), 533 { free_installations(install_paths, install_versions, count); }); 534 for(size_t i = 0; i < count; ++i) { 535 fprintf(log, "Found installation of %ld.%ld.%ld.%ld in: %s\n", install_versions[i].major, 536 install_versions[i].minor, install_versions[i].patch, install_versions[i].build, install_paths[i]); 537 } 538 fprintf(log, "\n"); 539 if(platform == PLATFORM_X64) { 540 CHECK_ERROR_HANDLED(remove_explicit_layers(log, install_paths, count, PLATFORM_X64), 541 { free_installations(install_paths, install_versions, count); }); 542 fprintf(log, "\n"); 543 } 544 CHECK_ERROR_HANDLED(remove_explicit_layers(log, install_paths, count, PLATFORM_X86), 545 { free_installations(install_paths, install_versions, count); }); 546 fprintf(log, "\n"); 547 548 if(version->major == 0 && version->minor == 0 && version->patch == 0 && version->build == 0) { 549 free_installations(install_paths, install_versions, count); 550 return 0; 551 } 552 553 for(size_t i = 0; i < count; ++i) { 554 if(compare_versions(install_versions + i, version) == 0) { 555 if(platform == PLATFORM_X64) { 556 CHECK_ERROR_HANDLED(add_explicit_layers(log, install_paths[i], PLATFORM_X64), 557 { free_installations(install_paths, install_versions, count); }); 558 fprintf(log, "\n"); 559 } 560 CHECK_ERROR_HANDLED(add_explicit_layers(log, install_paths[i], PLATFORM_X86), 561 { free_installations(install_paths, install_versions, count); }); 562 break; 563 } 564 } 565 free_installations(install_paths, install_versions, count); 566 return 0; 567 } 568 569 //int update_system_file(FILE* log, const char* name, const char* extension, const char* path, 570 // long abi_major, bool append_abi_major, struct SDKVersion* latest_version) 571 int update_system_file(FILE* log, const char* name, const char* extension, const char* path, 572 long abi_major, bool leave_abi_major, struct SDKVersion* latest_version) 573 { 574 // Generate the filter string 575 const char* pattern = "%s%s-%ld-*-*-*-*%s"; 576 int filter_size = snprintf(NULL, 0, pattern, path, name, abi_major, extension) + 1; 577 if(filter_size < 0) { 578 return 180; 579 } 580 char* filter = malloc(filter_size); 581 snprintf(filter, filter_size, pattern, path, name, abi_major, extension); 582 583 // Find all of the files that match the pattern 584 char* latest_filename = malloc(64); 585 memset(latest_version, 0, sizeof(struct SDKVersion)); 586 WIN32_FIND_DATA find_data; 587 HANDLE find = FindFirstFile(filter, &find_data); 588 free(filter); 589 for(bool at_end = (find != INVALID_HANDLE_VALUE); at_end; 590 at_end = FindNextFile(find, &find_data)) { 591 592 struct SDKVersion version; 593 CHECK_ERROR_HANDLED(read_version_from_filename(find_data.cFileName, &version), { free(latest_filename); }); 594 595 // Decide if this is the latest file 596 if(compare_versions(latest_version, &version) < 0) { 597 *latest_version = version; 598 const char* latestPattern = "%s%s"; 599 int size = snprintf(NULL, 0, latestPattern, path, find_data.cFileName) + 1; 600 if(size < 0) { 601 free(latest_filename); 602 return 200; 603 } 604 latest_filename = realloc(latest_filename, size); 605 snprintf(latest_filename, size, latestPattern, path, find_data.cFileName); 606 } 607 } 608 FindClose(find); 609 610 // Make sure something was found 611 if(latest_version->major == 0 && latest_version->minor == 0 && latest_version->patch == 0 && 612 latest_version->build == 0) { 613 fprintf(log, "Didn't find any version of %s%s\n", name, extension); 614 return 0; 615 } 616 617 fprintf(log, "Found latest version of %s%s: %ld.%ld.%ld.%ld\n", name, extension, latest_version->major, 618 latest_version->minor, latest_version->patch, latest_version->build); 619 620 // Generate output filename 621 char* output_filename; 622 if(leave_abi_major) { 623 const char* outPattern = "%s%s-%ld%s"; 624 int out_size = snprintf(NULL, 0, outPattern, path, name, abi_major, extension) + 1; 625 if(out_size < 0) { 626 free(latest_filename); 627 return 205; 628 } 629 output_filename = malloc(out_size); 630 snprintf(output_filename, out_size, outPattern, path, name, abi_major, extension); 631 } else { 632 const char* outPattern = "%s%s%s"; 633 int out_size = snprintf(NULL, 0, outPattern, path, name, extension) + 1; 634 if(out_size < 0) { 635 free(latest_filename); 636 return 210; 637 } 638 output_filename = malloc(out_size); 639 snprintf(output_filename, out_size, outPattern, path, name, extension); 640 } 641 642 // Remove any older version of the output file 643 if(remove(output_filename) == 0) { 644 fprintf(log, "Removed file %s\n", output_filename); 645 } else { 646 fprintf(log, "Did not remove file %s\n", output_filename); 647 } 648 649 fprintf(log, "Attempting to copy file %s to %s\n", latest_filename, output_filename); 650 if(CopyFile(latest_filename, output_filename, false) == 0) { 651 free(latest_filename); 652 free(output_filename); 653 return 215; 654 } 655 656 free(latest_filename); 657 free(output_filename); 658 return 0; 659 } 660 661 int update_windows_directories(FILE* log, long abi_major, enum Platform platform, struct SDKVersion* latest_runtime_version) 662 { 663 struct SDKVersion version; 664 unsigned windows_path_size = GetWindowsDirectory(NULL, 0); // Size includes null terminator 665 char* system_path = malloc(windows_path_size + 666 max_s(strlen(PATH_SYSTEM32), strlen(PATH_SYSWOW64))); 667 GetWindowsDirectory(system_path, windows_path_size); 668 669 strcpy(system_path + windows_path_size - 1, PATH_SYSTEM32); 670 fprintf(log, "Updating system directory: %s\n", system_path); 671 CHECK_ERROR_HANDLED(update_system_file(log, "vulkan", ".dll", system_path, abi_major, true, 672 latest_runtime_version), { free(system_path); }); 673 CHECK_ERROR_HANDLED(update_system_file(log, "vulkaninfo", ".exe", system_path, abi_major, false, 674 &version), { free(system_path); }); 675 if(compare_versions(latest_runtime_version, &version) != 0) { 676 free(system_path); 677 return 220; 678 } 679 680 if(platform == PLATFORM_X64) { 681 strcpy(system_path + windows_path_size - 1, PATH_SYSWOW64); 682 fprintf(log, "\nUpdating system directory: %s\n", system_path); 683 CHECK_ERROR_HANDLED(update_system_file(log, "vulkan", ".dll", system_path, abi_major, 684 true, &version), { free(system_path); }); 685 if(compare_versions(latest_runtime_version, &version) != 0) { 686 free(system_path); 687 return 230; 688 } 689 CHECK_ERROR_HANDLED(update_system_file(log, "vulkaninfo", ".exe", system_path, abi_major, 690 false, &version), { free(system_path); }); 691 if(compare_versions(latest_runtime_version, &version) != 0) { 692 free(system_path); 693 return 240; 694 } 695 } 696 697 free(system_path); 698 fprintf(log, "\nUpdate of system directories succeeded.\n\n"); 699 return 0; 700 } 701