1 /* 2 * PROJECT: ReactOS sdbinst 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Application compatibility database installer 5 * COPYRIGHT: Copyright 2020 Max Korostil (mrmks04@yandex.ru) 6 */ 7 8 #include <tchar.h> 9 10 #include <windef.h> 11 #include <winbase.h> 12 #include <winreg.h> 13 #include <strsafe.h> 14 #include <objbase.h> 15 #include <apphelp.h> 16 #include <shlwapi.h> 17 18 #define APPCOMPAT_CUSTOM_REG_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Custom" 19 #define APPCOMPAT_LAYERS_REG_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Custom\\Layers" 20 #define APPCOMPAT_INSTALLEDSDB_REG_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\InstalledSDB" 21 #define UNINSTALL_REG_PATH L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" 22 #define DBPATH_KEY_NAME L"DatabasePath" 23 #define SDB_EXT L".sdb" 24 #define GUID_STR_LENGTH 38 25 #define GUID_SBD_NAME_LENGTH (GUID_STR_LENGTH + ARRAYSIZE(SDB_EXT)) 26 27 BOOL SdbUninstallByGuid(_In_ LPWSTR guidSdbStr); 28 29 HRESULT 30 RegisterSdbEntry( 31 _In_ PWCHAR sdbEntryName, 32 _In_ LPCWSTR dbGuid, 33 _In_ ULONGLONG time, 34 _In_ BOOL isInstall, 35 _In_ BOOL isExe) 36 { 37 WCHAR regName[MAX_PATH]; 38 HKEY hKey = NULL; 39 LSTATUS status; 40 HRESULT hres; 41 42 hres = StringCchPrintfW(regName, MAX_PATH, L"%ls\\%ls", 43 isExe ? APPCOMPAT_CUSTOM_REG_PATH : APPCOMPAT_LAYERS_REG_PATH, 44 sdbEntryName); 45 if (FAILED(hres)) 46 { 47 wprintf(L"StringCchPrintfW error: 0x%08X\n", hres); 48 goto end; 49 } 50 51 // Remove key 52 if (!isInstall) 53 { 54 status = RegDeleteKeyW(HKEY_LOCAL_MACHINE, regName); 55 if (status == ERROR_FILE_NOT_FOUND) 56 { 57 status = ERROR_SUCCESS; 58 } 59 60 return HRESULT_FROM_WIN32(status); 61 } 62 63 // Create main key 64 status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 65 regName, 66 0, 67 NULL, 68 REG_OPTION_NON_VOLATILE, 69 KEY_ALL_ACCESS, 70 NULL, 71 &hKey, 72 NULL); 73 if (status != ERROR_SUCCESS) 74 { 75 wprintf(L"RegKeyCreateEx error: 0x%08X", status); 76 hres = HRESULT_FROM_WIN32(status); 77 goto end; 78 } 79 80 // Set installed time 81 status = RegSetValueExW(hKey, 82 dbGuid, 83 0, 84 REG_QWORD, 85 (PBYTE)&time, 86 sizeof(time)); 87 if (status != ERROR_SUCCESS) 88 { 89 wprintf(L"RegSetValueExW error: 0x%08X", status); 90 hres = HRESULT_FROM_WIN32(status); 91 goto end; 92 } 93 94 end: 95 if (hKey) 96 { 97 RegCloseKey(hKey); 98 } 99 100 return hres; 101 } 102 103 HRESULT 104 AddUninstallKey( 105 _In_ LPCWSTR dbName, 106 _In_ LPCWSTR sdbInstalledPath, 107 _In_ LPCWSTR guidDbStr) 108 { 109 WCHAR sdbinstPath[MAX_PATH]; 110 WCHAR regName[MAX_PATH]; 111 WCHAR uninstString[MAX_PATH]; 112 HKEY hKey = NULL; 113 HRESULT hres; 114 115 UINT count = GetSystemWindowsDirectory(sdbinstPath, MAX_PATH); 116 if (sdbinstPath[count - 1] != L'\\') 117 { 118 hres = StringCchCatW(sdbinstPath, MAX_PATH, L"\\"); 119 if (FAILED(hres)) 120 { 121 wprintf(L"StringCchCatW error: 0x%08X", hres); 122 goto end; 123 } 124 } 125 126 // Full path to sdbinst.exe 127 hres = StringCchCatW(sdbinstPath, MAX_PATH, L"System32\\sdbinst.exe"); 128 if (FAILED(hres)) 129 { 130 wprintf(L"StringCchCatW error: 0x%08X", hres); 131 goto end; 132 } 133 134 // Sdb GUID registry key 135 hres = StringCchPrintfW(regName, MAX_PATH, L"%ls\\%ls", UNINSTALL_REG_PATH, guidDbStr); 136 if (FAILED(hres)) 137 { 138 wprintf(L"StringCchPrintfW error: 0x%08X", hres); 139 goto end; 140 } 141 142 // Create main key 143 LSTATUS status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 144 regName, 145 0, 146 NULL, 147 REG_OPTION_NON_VOLATILE, 148 KEY_ALL_ACCESS, 149 NULL, 150 &hKey, 151 NULL); 152 153 if (status != ERROR_SUCCESS) 154 { 155 wprintf(L"RegKeyCreateEx error: 0x%08X", status); 156 hres = HRESULT_FROM_WIN32(status); 157 goto end; 158 } 159 160 // Set Display name 161 DWORD length = wcslen(dbName) * sizeof(WCHAR); 162 status = RegSetValueExW(hKey, 163 L"DisplayName", 164 0, 165 REG_SZ, 166 (PBYTE)dbName, 167 length + sizeof(WCHAR)); 168 if (status != ERROR_SUCCESS) 169 { 170 wprintf(L"RegSetValueExW error: 0x%08X", status); 171 hres = HRESULT_FROM_WIN32(status); 172 goto end; 173 } 174 175 // Uninstall full string 176 hres = StringCchPrintfW(uninstString, MAX_PATH, L"%ls -u \"%ls\"", sdbinstPath, sdbInstalledPath); 177 if (FAILED(hres)) 178 { 179 wprintf(L"StringCchPrintfW error: 0x%08X", hres); 180 goto end; 181 } 182 183 // Set uninstall string 184 length = wcslen(uninstString) * sizeof(WCHAR); 185 status = RegSetValueExW(hKey, 186 L"UninstallString", 187 0, 188 REG_SZ, 189 (PBYTE)uninstString, 190 length + sizeof(WCHAR)); 191 if (status != ERROR_SUCCESS) 192 { 193 wprintf(L"RegSetValueExW error: 0x%08X", status); 194 hres = HRESULT_FROM_WIN32(status); 195 goto end; 196 } 197 198 end: 199 if (hKey) 200 { 201 RegCloseKey(hKey); 202 } 203 204 return hres; 205 } 206 207 // 208 // Get database GUID id 209 // 210 BOOL 211 GetSdbGuid( 212 _In_ PDB pdb, 213 _In_ TAGID tagDb, 214 _Out_ GUID* guid) 215 { 216 TAGID tagDbId; 217 218 tagDbId = SdbFindFirstTag(pdb, tagDb, TAG_DATABASE_ID); 219 if (!tagDbId) 220 { 221 wprintf(L"Can't find database id tag"); 222 return FALSE; 223 } 224 225 if (!SdbReadBinaryTag(pdb, tagDbId, (PBYTE)guid, sizeof(GUID))) 226 { 227 wprintf(L"Can't read database id"); 228 return FALSE; 229 } 230 231 return TRUE; 232 } 233 234 HRESULT 235 ProcessLayers( 236 _In_ PDB pdb, 237 _In_ TAGID tagDb, 238 _In_opt_ LPCWSTR guidDbStr, 239 _In_opt_ ULONGLONG time, 240 _In_ BOOL isInstall) 241 { 242 HRESULT res = ERROR_SUCCESS; 243 TAGID tagLayerName; 244 TAGID prevTagLayer = 0; 245 246 TAGID tagLayer = SdbFindFirstTag(pdb, tagDb, TAG_LAYER); 247 248 // Add all layers to registry (AppCompatFlags) 249 while (tagLayer && (tagLayer != prevTagLayer)) 250 { 251 tagLayerName = SdbFindFirstTag(pdb, tagLayer, TAG_NAME); 252 if (!tagLayerName) 253 { 254 res = ERROR_NOT_FOUND; 255 break; 256 } 257 258 LPWSTR name = SdbGetStringTagPtr(pdb, tagLayerName); 259 260 res = RegisterSdbEntry(name, guidDbStr, time, isInstall, FALSE); 261 if (FAILED(res)) 262 { 263 wprintf(L"Can't register layer\n"); 264 break; 265 } 266 267 prevTagLayer = tagLayer; 268 tagLayer = SdbFindNextTag(pdb, tagDb, tagLayer); 269 } 270 271 return res; 272 } 273 274 HRESULT 275 ProcessExe( 276 _In_ PDB pdb, 277 _In_ TAGID tagDb, 278 _In_opt_ LPCWSTR guidDbStr, 279 _In_opt_ ULONGLONG time, 280 _In_ BOOL isInstall) 281 { 282 HRESULT res = ERROR_SUCCESS; 283 TAGID tagExeName; 284 TAGID tagExePrev = 0; 285 286 TAGID tagExe = SdbFindFirstTag(pdb, tagDb, TAG_EXE); 287 288 // Add all exe to registry (AppCompatFlags) 289 while (tagExe != 0 && (tagExe != tagExePrev)) 290 { 291 tagExeName = SdbFindFirstTag(pdb, tagExe, TAG_NAME); 292 if (!tagExeName) 293 { 294 wprintf(L"Can't find exe tag\n"); 295 res = ERROR_NOT_FOUND; 296 break; 297 } 298 299 LPWSTR name = SdbGetStringTagPtr(pdb, tagExeName); 300 301 res = RegisterSdbEntry(name, guidDbStr, time, isInstall, TRUE); 302 if (FAILED(res)) 303 { 304 wprintf(L"Can't register exe 0x%08X\n", res); 305 break; 306 } 307 308 tagExePrev = tagExe; 309 tagExe = SdbFindNextTag(pdb, tagDb, tagExe); 310 } 311 312 return res; 313 } 314 315 HRESULT 316 CopySdbToAppPatch( 317 _In_ LPCWSTR sourceSdbPath, 318 _In_ LPCWSTR destSdbPath) 319 { 320 DWORD error = ERROR_SUCCESS; 321 PWCHAR pTmpSysdir = NULL; 322 SIZE_T destLen = wcslen(destSdbPath); 323 PWCHAR sysdirPath = (PWCHAR)HeapAlloc(GetProcessHeap(), 0, destLen * sizeof(WCHAR)); 324 325 if (sysdirPath == NULL) 326 { 327 error = ERROR_NOT_ENOUGH_MEMORY; 328 goto end; 329 } 330 331 // Get parent folder fo sdb file 332 CopyMemory(sysdirPath, destSdbPath, destLen * sizeof(WCHAR)); 333 pTmpSysdir = StrRChrW(sysdirPath, sysdirPath + destLen, L'\\'); 334 if (pTmpSysdir == NULL) 335 { 336 wprintf(L"Can't find directory separator\n"); 337 goto end; 338 } 339 else 340 { 341 *pTmpSysdir = UNICODE_NULL; 342 } 343 344 // Create directory if need 345 if (!CreateDirectory(sysdirPath, NULL)) 346 { 347 error = GetLastError(); 348 if (error != ERROR_ALREADY_EXISTS) 349 { 350 wprintf(L"Can't create folder %ls\n Error: 0x%08X\n", sysdirPath, error); 351 goto end; 352 } 353 error = ERROR_SUCCESS; 354 } 355 356 // Copy file 357 if (!CopyFile(sourceSdbPath, destSdbPath, TRUE)) 358 { 359 error = GetLastError(); 360 wprintf(L"Can't copy sdb file"); 361 } 362 363 end: 364 if (sysdirPath) 365 { 366 HeapFree(GetProcessHeap(), 0, sysdirPath); 367 } 368 369 return HRESULT_FROM_WIN32(error); 370 } 371 372 HRESULT 373 BuildPathToSdb( 374 _In_ PWCHAR buffer, 375 _In_ SIZE_T bufLen, 376 _In_ LPCWSTR guidDbStr) 377 { 378 ZeroMemory(buffer, bufLen * sizeof(WCHAR)); 379 380 // Can't use here SdbGetAppPatchDir, because Windows XP haven't this function 381 UINT count = GetSystemWindowsDirectory(buffer, bufLen); 382 if (buffer[count - 1] != L'\\') 383 { 384 buffer[count] = L'\\'; 385 } 386 387 HRESULT res = StringCchCatW(buffer, bufLen, L"AppPatch\\Custom\\"); 388 if (FAILED(res)) 389 { 390 goto end; 391 } 392 393 res = StringCchCatW(buffer, bufLen, guidDbStr); 394 395 end: 396 return res; 397 } 398 399 BOOL 400 SdbInstall( 401 _In_ LPCWSTR sdbPath) 402 { 403 BOOL res = FALSE; 404 PDB pdb = NULL; 405 TAGID tagDb; 406 TAGID tagDbName; 407 GUID dbGuid = {0}; 408 FILETIME systemTime = {0}; 409 ULARGE_INTEGER currentTime = {0}; 410 WCHAR sysdirPatchPath[MAX_PATH]; 411 WCHAR guidDbStr[GUID_SBD_NAME_LENGTH]; 412 413 GetSystemTimeAsFileTime(&systemTime); 414 currentTime.LowPart = systemTime.dwLowDateTime; 415 currentTime.HighPart = systemTime.dwHighDateTime; 416 417 // Open database 418 pdb = SdbOpenDatabase(sdbPath, DOS_PATH); 419 if (pdb == NULL) 420 { 421 wprintf(L"Can't open database %ls\n", sdbPath); 422 goto end; 423 } 424 425 tagDb = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE); 426 if (!tagDb) 427 { 428 wprintf(L"Can't find database tag\n"); 429 goto end; 430 } 431 432 // Get database GUID 433 if (!GetSdbGuid(pdb, tagDb, &dbGuid)) 434 { 435 wprintf(L"GetSdbGuid error\n"); 436 goto end; 437 } 438 439 StringFromGUID2(&dbGuid, guidDbStr, GUID_SBD_NAME_LENGTH); 440 HRESULT hres = StringCchCatW(guidDbStr, GUID_SBD_NAME_LENGTH, SDB_EXT); 441 if (FAILED(hres)) 442 { 443 wprintf(L"StringCchCatW error 0x%08X\n", hres); 444 goto end; 445 } 446 447 wprintf(L"Database guid %ls\n", guidDbStr); 448 449 tagDbName = SdbFindFirstTag(pdb, tagDb, TAG_NAME); 450 if (!tagDbName) 451 { 452 wprintf(L"Can't get tag name\n"); 453 goto end; 454 } 455 456 LPWSTR dbName = SdbGetStringTagPtr(pdb, tagDbName); 457 wprintf(L"Database name %ls\n", dbName); 458 459 // Process exe tags 460 hres = ProcessExe(pdb, tagDb, guidDbStr, currentTime.QuadPart, TRUE); 461 if (FAILED(hres)) 462 { 463 wprintf(L"Process exe failed. Status: 0x%08X", res); 464 goto end; 465 } 466 467 // Proess layer tags 468 hres = ProcessLayers(pdb, tagDb, guidDbStr, currentTime.QuadPart, TRUE); 469 if (FAILED(hres)) 470 { 471 wprintf(L"Process layers failed. Status: 0x%08X", res); 472 goto end; 473 } 474 475 // Create full path to sdb in system folder 476 hres = BuildPathToSdb(sysdirPatchPath, ARRAYSIZE(sysdirPatchPath), guidDbStr); 477 if (FAILED(hres)) 478 { 479 wprintf(L"Build path error\n"); 480 goto end; 481 } 482 483 wprintf(L"file path %ls\n", sysdirPatchPath); 484 485 res = CopySdbToAppPatch(sdbPath, sysdirPatchPath); 486 if (FAILED(res)) 487 { 488 wprintf(L"Copy sdb error. Status: 0x%08X\n", res); 489 goto end; 490 } 491 492 AddUninstallKey(dbName, sysdirPatchPath, guidDbStr); 493 494 // Registration 495 if (!SdbRegisterDatabaseEx(sysdirPatchPath, SDB_DATABASE_SHIM, ¤tTime.QuadPart)) 496 { 497 wprintf(L"SdbRegisterDatabaseEx failed"); 498 goto end; 499 } 500 501 res = TRUE; 502 503 end: 504 if (pdb) 505 { 506 SdbCloseDatabase(pdb); 507 } 508 509 return res; 510 } 511 512 HRESULT 513 DeleteUninstallKey( 514 _In_ LPCWSTR keyName) 515 { 516 HKEY hKey = NULL; 517 HRESULT hres = HRESULT_FROM_WIN32(ERROR_SUCCESS); 518 519 LSTATUS status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 520 UNINSTALL_REG_PATH, 521 0, 522 NULL, 523 REG_OPTION_NON_VOLATILE, 524 KEY_ALL_ACCESS, 525 NULL, 526 &hKey, 527 NULL); 528 529 if (status != ERROR_SUCCESS) 530 { 531 hres = HRESULT_FROM_WIN32(status); 532 goto end; 533 } 534 535 status = RegDeleteKeyW(hKey, keyName); 536 if (status != ERROR_SUCCESS) 537 { 538 hres = HRESULT_FROM_WIN32(status); 539 } 540 541 end: 542 if (hKey) 543 { 544 RegCloseKey(hKey); 545 } 546 547 return hres; 548 } 549 550 BOOL 551 SdbUninstall( 552 _In_ LPWSTR sdbPath) 553 { 554 BOOL res = FALSE; 555 PWCHAR sdbName = NULL; 556 PDB pdb; 557 TAGID tagDb; 558 GUID dbGuid = {0}; 559 WCHAR guidDbStr[GUID_SBD_NAME_LENGTH]; 560 561 SIZE_T sdbPathLen = wcslen(sdbPath); 562 sdbName = sdbPath + sdbPathLen; 563 564 wprintf(L"uninstall path %ls\n", sdbPath); 565 sdbName = StrRChrW(sdbPath, sdbPath + sdbPathLen, L'\\'); 566 if (sdbName == NULL) 567 { 568 sdbName = sdbPath; 569 } 570 else 571 { 572 sdbName++; 573 } 574 575 wprintf(L"uninstall name %ls\n", sdbName); 576 577 // open sdb 578 pdb = SdbOpenDatabase(sdbPath, DOS_PATH); 579 if (pdb == NULL) 580 { 581 wprintf(L"Can't open database %ls\n", sdbPath); 582 return FALSE; 583 } 584 585 tagDb = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE); 586 if (!tagDb) 587 { 588 wprintf(L"Can't find database tag\n"); 589 goto end; 590 } 591 592 if (!GetSdbGuid(pdb, tagDb, &dbGuid)) 593 { 594 wprintf(L"GetSdbGuid error\n"); 595 goto end; 596 } 597 598 // Database name must be GUID string 599 if (wcslen(sdbName) + 1 != GUID_SBD_NAME_LENGTH) 600 { 601 StringFromGUID2(&dbGuid, guidDbStr, GUID_SBD_NAME_LENGTH); 602 SdbCloseDatabase(pdb); 603 return SdbUninstallByGuid(guidDbStr); 604 } 605 606 //remove regkey in appatch/custom 607 HRESULT hres = ProcessExe(pdb, tagDb, NULL, 0, FALSE); 608 if (FAILED(hres)) 609 { 610 wprintf(L"Process exe fail\n"); 611 goto end; 612 } 613 614 hres = ProcessLayers(pdb, tagDb, NULL, 0, FALSE); 615 if (FAILED(hres)) 616 { 617 wprintf(L"Process layers fail\n"); 618 goto end; 619 } 620 621 SdbCloseDatabase(pdb); 622 pdb = NULL; 623 624 hres = DeleteUninstallKey(sdbName); 625 if (FAILED(hres)) 626 { 627 wprintf(L"Remove uninstall key fail\n"); 628 } 629 630 if (!SdbUnregisterDatabase(&dbGuid)) 631 { 632 wprintf(L"SdbUnregisterDatabase\n"); 633 return FALSE; 634 } 635 636 SetFileAttributesW(sdbPath, FILE_ATTRIBUTE_NORMAL); 637 if (!DeleteFileW(sdbPath)) 638 { 639 wprintf(L"Remove file fail 0x%08X\n", GetLastError()); 640 return FALSE; 641 } 642 643 res = TRUE; 644 645 end: 646 if (pdb) 647 SdbCloseDatabase(pdb); 648 return res; 649 } 650 651 BOOL 652 ValidateGuidString( 653 _In_ PWCHAR guidStr) 654 { 655 ULONG length = wcslen(guidStr); 656 657 if (length == GUID_STR_LENGTH && 658 guidStr[0] == L'{' && 659 guidStr[GUID_STR_LENGTH - 1] == L'}' && 660 guidStr[9] == L'-' && 661 guidStr[14] == L'-' && 662 guidStr[19] == L'-' && 663 guidStr[24] == L'-') 664 { 665 return TRUE; 666 } 667 668 return FALSE; 669 } 670 671 BOOL 672 SdbUninstallByGuid( 673 _In_ LPWSTR guidSdbStr) 674 { 675 BOOL res = FALSE; 676 HKEY hKey = NULL; 677 HKEY guidKey = NULL; 678 LSTATUS status; 679 WCHAR dbPath[MAX_PATH]; 680 DWORD keyValSize = sizeof(dbPath); 681 682 if (!ValidateGuidString(guidSdbStr)) 683 { 684 wprintf(L"Invalid GUID: %ls\n", guidSdbStr); 685 return res; 686 } 687 688 status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, APPCOMPAT_INSTALLEDSDB_REG_PATH, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); 689 690 if (status != ERROR_SUCCESS) 691 { 692 wprintf(L"RegOpenKeyW error: 0x%08X", status); 693 goto end; 694 } 695 696 status = RegOpenKeyExW(hKey, guidSdbStr, 0, KEY_READ | KEY_QUERY_VALUE, &guidKey); 697 698 if (status != ERROR_SUCCESS) 699 { 700 wprintf(L"Cant open key: 0x%08X %ls\n", status, guidSdbStr); 701 goto end; 702 } 703 704 status = RegQueryValueExW(guidKey, DBPATH_KEY_NAME, NULL, NULL, (LPBYTE)dbPath, &keyValSize); 705 if (status != ERROR_SUCCESS) 706 { 707 wprintf(L"RegQueryValueExW: 0x%08X\n", status); 708 goto end; 709 } 710 711 res = SdbUninstall(dbPath); 712 713 end: 714 if (hKey) 715 { 716 RegCloseKey(hKey); 717 } 718 719 if (guidKey) 720 { 721 RegCloseKey(guidKey); 722 } 723 724 return res; 725 } 726 727 BOOL 728 SdbUninstallByName( 729 _In_ LPWSTR nameSdbStr) 730 { 731 BOOL res = FALSE; 732 LSTATUS status; 733 HKEY hKey = NULL; 734 HKEY subKey = NULL; 735 DWORD index = 0; 736 WCHAR keyName[MAX_PATH]; 737 DWORD keyNameLen = ARRAYSIZE(keyName); 738 DWORD keyValSize; 739 WCHAR dbDescript[MAX_PATH]; 740 WCHAR dbPath[MAX_PATH]; 741 742 status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, APPCOMPAT_INSTALLEDSDB_REG_PATH, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); 743 744 if (status != ERROR_SUCCESS) 745 { 746 wprintf(L"RegOpenKeyW error: 0x%08X", status); 747 goto end; 748 } 749 750 status = RegEnumKeyEx(hKey, index, keyName, &keyNameLen, NULL, NULL, NULL, NULL); 751 wprintf(L"0x%08X %d %ls \n", status, keyNameLen, keyName); 752 753 // Search database GUID by name 754 while (status == ERROR_SUCCESS) 755 { 756 status = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | KEY_QUERY_VALUE, &subKey); 757 if (status != ERROR_SUCCESS) 758 { 759 break; 760 } 761 762 keyValSize = sizeof(dbDescript); 763 status = RegQueryValueExW(subKey, L"DatabaseDescription", NULL, NULL, (LPBYTE)dbDescript, &keyValSize); 764 if (status != ERROR_SUCCESS) 765 { 766 break; 767 } 768 769 wprintf(L"dbdescript: %ls \n", dbDescript); 770 771 if (_wcsnicmp(dbDescript, nameSdbStr, keyNameLen) == 0) 772 { 773 // Take db full path 774 keyValSize = sizeof(dbPath); 775 status = RegQueryValueExW(subKey, DBPATH_KEY_NAME, NULL, NULL, (LPBYTE)dbPath, &keyValSize); 776 if (status != ERROR_SUCCESS) 777 { 778 dbPath[0] = UNICODE_NULL; 779 break; 780 } 781 782 wprintf(L"dbpath: 0x%08X %ls \n", status, dbPath); 783 RegCloseKey(subKey); 784 break; 785 } 786 787 RegCloseKey(subKey); 788 789 keyName[0] = UNICODE_NULL; 790 791 ++index; 792 keyNameLen = ARRAYSIZE(keyName); 793 status = RegEnumKeyExW(hKey, index, keyName, &keyNameLen, NULL, NULL, NULL, NULL); 794 } 795 796 RegCloseKey(hKey); 797 798 if (dbPath[0] != UNICODE_NULL) 799 { 800 res = SdbUninstall(dbPath); 801 } 802 803 end: 804 return res; 805 } 806 807 808 void 809 ShowHelp() 810 { 811 /* FIXME: to be localized */ 812 wprintf(L"Using: sdbinst [-?][-q][-u][-g][-n] foo.sdb | {guid} | \"name\" \n" 813 L"-? - show help\n" 814 L"-u - uninstall\n" 815 L"-g - {guid} file GUID (only uninstall)\n" 816 L"-n - \"name\" - file name (only uninstall)\n"); 817 } 818 819 int _tmain(int argc, LPWSTR argv[]) 820 { 821 LPWSTR sdbPath = NULL; 822 BOOL isInstall = TRUE; 823 BOOL isUninstByGuid = FALSE; 824 BOOL isUninstByName = FALSE; 825 BOOL success = FALSE; 826 LPWSTR guidSdbStr = NULL; 827 LPWSTR nameSdbStr = NULL; 828 829 if (argc < 2) 830 { 831 ShowHelp(); 832 } 833 834 for (int i = 1; i < argc; ++i) 835 { 836 if (argv[i][0] != L'-') 837 { 838 sdbPath = argv[i]; 839 break; 840 } 841 842 switch (argv[i][1]) 843 { 844 case L'?': 845 ShowHelp(); 846 return ERROR_SUCCESS; 847 break; 848 849 case L'u': 850 isInstall = FALSE; 851 break; 852 853 case L'g': 854 ++i; 855 856 if (i >= argc) 857 { 858 return ERROR_INVALID_PARAMETER; 859 } 860 861 guidSdbStr = argv[i]; 862 wprintf(L"guidSdbStr %ls\n", guidSdbStr); 863 864 isUninstByGuid = TRUE; 865 isInstall = FALSE; 866 break; 867 868 case L'n': 869 ++i; 870 871 if (i >= argc) 872 { 873 return ERROR_INVALID_PARAMETER; 874 } 875 876 nameSdbStr = argv[i]; 877 wprintf(L"nameSdbStr %ls\n", nameSdbStr); 878 879 isUninstByName = TRUE; 880 isInstall = FALSE; 881 break; 882 } 883 } 884 885 if (isInstall) 886 { 887 wprintf(L"install\n"); 888 success = SdbInstall(sdbPath); 889 } 890 else if (isUninstByGuid) 891 { 892 wprintf(L"uninstall by GUID\n"); 893 success = SdbUninstallByGuid(guidSdbStr); 894 } 895 else if (isUninstByName) 896 { 897 wprintf(L"uninstall by name\n"); 898 success = SdbUninstallByName(nameSdbStr); 899 } 900 else 901 { 902 wprintf(L"uninstall\n"); 903 success = SdbUninstall(sdbPath); 904 } 905 906 if (!success) 907 { 908 wprintf(isInstall ? L"Sdb install failed\n" : L"Sdb uninstall failed\n"); 909 return -1; 910 } 911 912 return ERROR_SUCCESS; 913 } 914