1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2004,2005 Aric Stewart for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 23 #define COBJMACROS 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winerror.h" 28 #include "winreg.h" 29 #include "winsvc.h" 30 #include "odbcinst.h" 31 #include "wine/debug.h" 32 #include "msidefs.h" 33 #include "winuser.h" 34 #include "shlobj.h" 35 #include "objbase.h" 36 #include "mscoree.h" 37 #include "shlwapi.h" 38 #include "imagehlp.h" 39 #include "winver.h" 40 41 #include "msipriv.h" 42 #include "resource.h" 43 44 #define REG_PROGRESS_VALUE 13200 45 #define COMPONENT_PROGRESS_VALUE 24000 46 47 WINE_DEFAULT_DEBUG_CHANNEL(msi); 48 49 struct dummy_thread 50 { 51 HANDLE started; 52 HANDLE stopped; 53 HANDLE thread; 54 }; 55 56 static INT ui_actionstart(MSIPACKAGE *package, LPCWSTR action, LPCWSTR description, LPCWSTR template) 57 { 58 MSIRECORD *row, *textrow; 59 INT rc; 60 61 textrow = MSI_QueryGetRecord(package->db, L"SELECT * FROM `ActionText` WHERE `Action` = '%s'", action); 62 if (textrow) 63 { 64 description = MSI_RecordGetString(textrow, 2); 65 template = MSI_RecordGetString(textrow, 3); 66 } 67 68 row = MSI_CreateRecord(3); 69 if (!row) return -1; 70 MSI_RecordSetStringW(row, 1, action); 71 MSI_RecordSetStringW(row, 2, description); 72 MSI_RecordSetStringW(row, 3, template); 73 rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row); 74 if (textrow) msiobj_release(&textrow->hdr); 75 msiobj_release(&row->hdr); 76 return rc; 77 } 78 79 static void ui_actioninfo(MSIPACKAGE *package, const WCHAR *action, BOOL start, INT rc) 80 { 81 MSIRECORD *row; 82 WCHAR *template; 83 84 template = msi_get_error_message(package->db, start ? MSIERR_INFO_ACTIONSTART : MSIERR_INFO_ACTIONENDED); 85 86 row = MSI_CreateRecord(2); 87 if (!row) 88 { 89 free(template); 90 return; 91 } 92 MSI_RecordSetStringW(row, 0, template); 93 MSI_RecordSetStringW(row, 1, action); 94 MSI_RecordSetInteger(row, 2, start ? package->LastActionResult : rc); 95 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row); 96 msiobj_release(&row->hdr); 97 free(template); 98 if (!start) package->LastActionResult = rc; 99 } 100 101 enum parse_state 102 { 103 state_whitespace, 104 state_token, 105 state_quote 106 }; 107 108 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes ) 109 { 110 enum parse_state state = state_quote; 111 const WCHAR *p; 112 WCHAR *out = value; 113 BOOL ignore, in_quotes = FALSE; 114 int count = 0, len = 0; 115 116 for (p = str; *p; p++) 117 { 118 ignore = FALSE; 119 switch (state) 120 { 121 case state_whitespace: 122 switch (*p) 123 { 124 case ' ': 125 in_quotes = TRUE; 126 ignore = TRUE; 127 len++; 128 break; 129 case '"': 130 state = state_quote; 131 if (in_quotes && p[1] != '\"') count--; 132 else count++; 133 break; 134 default: 135 state = state_token; 136 in_quotes = TRUE; 137 len++; 138 break; 139 } 140 break; 141 142 case state_token: 143 switch (*p) 144 { 145 case '"': 146 state = state_quote; 147 if (in_quotes) count--; 148 else count++; 149 break; 150 case ' ': 151 state = state_whitespace; 152 if (!count) goto done; 153 in_quotes = TRUE; 154 len++; 155 break; 156 default: 157 if (count) in_quotes = TRUE; 158 len++; 159 break; 160 } 161 break; 162 163 case state_quote: 164 switch (*p) 165 { 166 case '"': 167 if (in_quotes && p[1] != '\"') count--; 168 else count++; 169 break; 170 case ' ': 171 state = state_whitespace; 172 if (!count || (count > 1 && !len)) goto done; 173 in_quotes = TRUE; 174 len++; 175 break; 176 default: 177 state = state_token; 178 if (count) in_quotes = TRUE; 179 len++; 180 break; 181 } 182 break; 183 184 default: break; 185 } 186 if (!ignore && value) *out++ = *p; 187 if (!count) in_quotes = FALSE; 188 } 189 190 done: 191 if (value) 192 { 193 if (!len) *value = 0; 194 else *out = 0; 195 } 196 197 if(quotes) *quotes = count; 198 return p - str; 199 } 200 201 static void remove_quotes( WCHAR *str ) 202 { 203 WCHAR *p = str; 204 int len = lstrlenW( str ); 205 206 while ((p = wcschr( p, '"' ))) 207 { 208 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) ); 209 p++; 210 } 211 } 212 213 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine, 214 BOOL preserve_case ) 215 { 216 LPCWSTR ptr, ptr2; 217 int num_quotes; 218 DWORD len; 219 WCHAR *prop, *val; 220 UINT r; 221 222 if (!szCommandLine) 223 return ERROR_SUCCESS; 224 225 ptr = szCommandLine; 226 while (*ptr) 227 { 228 while (*ptr == ' ') ptr++; 229 if (!*ptr) break; 230 231 ptr2 = wcschr( ptr, '=' ); 232 if (!ptr2) return ERROR_INVALID_COMMAND_LINE; 233 234 len = ptr2 - ptr; 235 if (!len) return ERROR_INVALID_COMMAND_LINE; 236 237 while (ptr[len - 1] == ' ') len--; 238 239 prop = malloc( (len + 1) * sizeof(WCHAR) ); 240 memcpy( prop, ptr, len * sizeof(WCHAR) ); 241 prop[len] = 0; 242 if (!preserve_case) wcsupr( prop ); 243 244 ptr2++; 245 while (*ptr2 == ' ') ptr2++; 246 247 num_quotes = 0; 248 val = malloc( (wcslen( ptr2 ) + 1) * sizeof(WCHAR) ); 249 len = parse_prop( ptr2, val, &num_quotes ); 250 if (num_quotes % 2) 251 { 252 WARN("unbalanced quotes\n"); 253 free( val ); 254 free( prop ); 255 return ERROR_INVALID_COMMAND_LINE; 256 } 257 remove_quotes( val ); 258 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val)); 259 260 r = msi_set_property( package->db, prop, val, -1 ); 261 if (r == ERROR_SUCCESS && !wcscmp( prop, L"SourceDir" )) 262 msi_reset_source_folders( package ); 263 264 free( val ); 265 free( prop ); 266 267 ptr = ptr2 + len; 268 } 269 270 return ERROR_SUCCESS; 271 } 272 273 const WCHAR *msi_get_command_line_option(const WCHAR *cmd, const WCHAR *option, UINT *len) 274 { 275 DWORD opt_len = lstrlenW(option); 276 277 if (!cmd) 278 return NULL; 279 280 while (*cmd) 281 { 282 BOOL found = FALSE; 283 284 while (*cmd == ' ') cmd++; 285 if (!*cmd) break; 286 287 if(!wcsnicmp(cmd, option, opt_len)) 288 found = TRUE; 289 290 cmd = wcschr( cmd, '=' ); 291 if(!cmd) break; 292 cmd++; 293 while (*cmd == ' ') cmd++; 294 if (!*cmd) break; 295 296 *len = parse_prop( cmd, NULL, NULL); 297 if (found) return cmd; 298 cmd += *len; 299 } 300 301 return NULL; 302 } 303 304 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep ) 305 { 306 LPCWSTR pc; 307 LPWSTR p, *ret = NULL; 308 UINT count = 0; 309 310 if (!str) 311 return ret; 312 313 /* count the number of substrings */ 314 for ( pc = str, count = 0; pc; count++ ) 315 { 316 pc = wcschr( pc, sep ); 317 if (pc) 318 pc++; 319 } 320 321 /* allocate space for an array of substring pointers and the substrings */ 322 ret = malloc( (count + 1) * sizeof(WCHAR *) + (wcslen(str) + 1) * sizeof(WCHAR) ); 323 if (!ret) 324 return ret; 325 326 /* copy the string and set the pointers */ 327 p = (LPWSTR) &ret[count+1]; 328 lstrcpyW( p, str ); 329 for( count = 0; (ret[count] = p); count++ ) 330 { 331 p = wcschr( p, sep ); 332 if (p) 333 *p++ = 0; 334 } 335 336 return ret; 337 } 338 339 static BOOL ui_sequence_exists( MSIPACKAGE *package ) 340 { 341 MSIQUERY *view; 342 DWORD count = 0; 343 344 if (!(MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0", &view ))) 345 { 346 MSI_IterateRecords( view, &count, NULL, package ); 347 msiobj_release( &view->hdr ); 348 } 349 return count != 0; 350 } 351 352 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace) 353 { 354 WCHAR *source, *check, *p, *db; 355 DWORD len; 356 357 if (!(db = msi_dup_property( package->db, L"OriginalDatabase" ))) 358 return ERROR_OUTOFMEMORY; 359 360 if (!(p = wcsrchr( db, '\\' )) && !(p = wcsrchr( db, '/' ))) 361 { 362 free(db); 363 return ERROR_SUCCESS; 364 } 365 len = p - db + 2; 366 source = malloc( len * sizeof(WCHAR) ); 367 lstrcpynW( source, db, len ); 368 free( db ); 369 370 check = msi_dup_property( package->db, L"SourceDir" ); 371 if (!check || replace) 372 { 373 UINT r = msi_set_property( package->db, L"SourceDir", source, -1 ); 374 if (r == ERROR_SUCCESS) 375 msi_reset_source_folders( package ); 376 } 377 free( check ); 378 379 check = msi_dup_property( package->db, L"SOURCEDIR" ); 380 if (!check || replace) 381 msi_set_property( package->db, L"SOURCEDIR", source, -1 ); 382 383 free( check ); 384 free( source ); 385 386 return ERROR_SUCCESS; 387 } 388 389 static BOOL needs_ui_sequence(MSIPACKAGE *package) 390 { 391 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED; 392 } 393 394 UINT msi_set_context(MSIPACKAGE *package) 395 { 396 UINT r = msi_locate_product( package->ProductCode, &package->Context ); 397 if (r != ERROR_SUCCESS) 398 { 399 int num = msi_get_property_int( package->db, L"ALLUSERS", 0 ); 400 if (num == 1 || num == 2) 401 package->Context = MSIINSTALLCONTEXT_MACHINE; 402 else 403 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED; 404 } 405 return ERROR_SUCCESS; 406 } 407 408 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) 409 { 410 UINT rc; 411 LPCWSTR cond, action; 412 MSIPACKAGE *package = param; 413 414 action = MSI_RecordGetString(row,1); 415 if (!action) 416 { 417 ERR("Error is retrieving action name\n"); 418 return ERROR_FUNCTION_FAILED; 419 } 420 421 /* check conditions */ 422 cond = MSI_RecordGetString(row,2); 423 424 /* this is a hack to skip errors in the condition code */ 425 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) 426 { 427 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action)); 428 return ERROR_SUCCESS; 429 } 430 431 rc = ACTION_PerformAction(package, action); 432 433 msi_dialog_check_messages( NULL ); 434 435 if (rc == ERROR_FUNCTION_NOT_CALLED) 436 rc = ERROR_SUCCESS; 437 438 if (rc != ERROR_SUCCESS) 439 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc); 440 441 if (package->need_reboot_now) 442 { 443 TRACE("action %s asked for immediate reboot, suspending installation\n", 444 debugstr_w(action)); 445 rc = ACTION_ForceReboot( package ); 446 } 447 return rc; 448 } 449 450 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table ) 451 { 452 MSIQUERY *view; 453 UINT r; 454 455 TRACE("%p %s\n", package, debugstr_w(table)); 456 457 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s` WHERE `Sequence` > 0 ORDER BY `Sequence`", table ); 458 if (r == ERROR_SUCCESS) 459 { 460 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package ); 461 msiobj_release(&view->hdr); 462 } 463 return r; 464 } 465 466 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package) 467 { 468 MSIQUERY *view; 469 UINT rc; 470 471 if (package->ExecuteSequenceRun) 472 { 473 TRACE("Execute Sequence already Run\n"); 474 return ERROR_SUCCESS; 475 } 476 477 package->ExecuteSequenceRun = TRUE; 478 479 rc = MSI_OpenQuery(package->db, &view, 480 L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` > 0 ORDER BY `Sequence`"); 481 if (rc == ERROR_SUCCESS) 482 { 483 TRACE("Running the actions\n"); 484 485 msi_set_property( package->db, L"SourceDir", NULL, -1 ); 486 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package); 487 msiobj_release(&view->hdr); 488 } 489 return rc; 490 } 491 492 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) 493 { 494 MSIQUERY *view; 495 UINT rc; 496 497 rc = MSI_DatabaseOpenViewW(package->db, 498 L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0 ORDER BY `Sequence`", 499 &view); 500 if (rc == ERROR_SUCCESS) 501 { 502 TRACE("Running the actions\n"); 503 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package); 504 msiobj_release(&view->hdr); 505 } 506 return rc; 507 } 508 509 /******************************************************** 510 * ACTION helper functions and functions that perform the actions 511 *******************************************************/ 512 static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action) 513 { 514 UINT arc; 515 INT uirc; 516 517 uirc = ui_actionstart(package, action, NULL, NULL); 518 if (uirc == IDCANCEL) 519 return ERROR_INSTALL_USEREXIT; 520 ui_actioninfo(package, action, TRUE, 0); 521 arc = ACTION_CustomAction(package, action); 522 uirc = !arc; 523 524 if (arc == ERROR_FUNCTION_NOT_CALLED && needs_ui_sequence(package)) 525 { 526 uirc = ACTION_ShowDialog(package, action); 527 switch (uirc) 528 { 529 case -1: 530 return ERROR_SUCCESS; /* stop immediately */ 531 case 0: arc = ERROR_FUNCTION_NOT_CALLED; break; 532 case 1: arc = ERROR_SUCCESS; break; 533 case 2: arc = ERROR_INSTALL_USEREXIT; break; 534 case 3: arc = ERROR_INSTALL_FAILURE; break; 535 case 4: arc = ERROR_INSTALL_SUSPEND; break; 536 case 5: arc = ERROR_MORE_DATA; break; 537 case 6: arc = ERROR_INVALID_HANDLE_STATE; break; 538 case 7: arc = ERROR_INVALID_DATA; break; 539 case 8: arc = ERROR_INSTALL_ALREADY_RUNNING; break; 540 case 9: arc = ERROR_INSTALL_PACKAGE_REJECTED; break; 541 default: arc = ERROR_FUNCTION_FAILED; break; 542 } 543 } 544 545 ui_actioninfo(package, action, FALSE, uirc); 546 547 return arc; 548 } 549 550 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component ) 551 { 552 MSICOMPONENT *comp; 553 554 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 555 { 556 if (!wcscmp( Component, comp->Component )) return comp; 557 } 558 return NULL; 559 } 560 561 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature ) 562 { 563 MSIFEATURE *feature; 564 565 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 566 { 567 if (!wcscmp( Feature, feature->Feature )) return feature; 568 } 569 return NULL; 570 } 571 572 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key ) 573 { 574 MSIFILE *file; 575 576 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 577 { 578 if (!wcscmp( key, file->File )) return file; 579 } 580 return NULL; 581 } 582 583 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir ) 584 { 585 MSIFOLDER *folder; 586 587 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry ) 588 { 589 if (!wcscmp( dir, folder->Directory )) return folder; 590 } 591 return NULL; 592 } 593 594 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d ) 595 { 596 MSIRECORD *row; 597 598 row = MSI_CreateRecord( 4 ); 599 MSI_RecordSetInteger( row, 1, a ); 600 MSI_RecordSetInteger( row, 2, b ); 601 MSI_RecordSetInteger( row, 3, c ); 602 MSI_RecordSetInteger( row, 4, d ); 603 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row ); 604 msiobj_release( &row->hdr ); 605 606 msi_dialog_check_messages( NULL ); 607 } 608 609 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp ) 610 { 611 if (!comp->Enabled) 612 { 613 TRACE("component is disabled: %s\n", debugstr_w(comp->Component)); 614 return INSTALLSTATE_UNKNOWN; 615 } 616 if (package->need_rollback) return comp->Installed; 617 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT) 618 { 619 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients); 620 return INSTALLSTATE_UNKNOWN; 621 } 622 return comp->ActionRequest; 623 } 624 625 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature ) 626 { 627 if (package->need_rollback) return feature->Installed; 628 return feature->ActionRequest; 629 } 630 631 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) 632 { 633 MSIPACKAGE *package = param; 634 LPCWSTR dir, component, full_path; 635 MSIRECORD *uirow; 636 MSIFOLDER *folder; 637 MSICOMPONENT *comp; 638 639 component = MSI_RecordGetString(row, 2); 640 if (!component) 641 return ERROR_SUCCESS; 642 643 comp = msi_get_loaded_component(package, component); 644 if (!comp) 645 return ERROR_SUCCESS; 646 647 comp->Action = msi_get_component_action( package, comp ); 648 if (comp->Action != INSTALLSTATE_LOCAL) 649 { 650 TRACE("component not scheduled for installation: %s\n", debugstr_w(component)); 651 return ERROR_SUCCESS; 652 } 653 654 dir = MSI_RecordGetString(row,1); 655 if (!dir) 656 { 657 ERR("Unable to get folder id\n"); 658 return ERROR_SUCCESS; 659 } 660 661 uirow = MSI_CreateRecord(1); 662 MSI_RecordSetStringW(uirow, 1, dir); 663 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 664 msiobj_release(&uirow->hdr); 665 666 full_path = msi_get_target_folder( package, dir ); 667 if (!full_path) 668 { 669 ERR("Unable to retrieve folder %s\n", debugstr_w(dir)); 670 return ERROR_SUCCESS; 671 } 672 TRACE("folder is %s\n", debugstr_w(full_path)); 673 674 folder = msi_get_loaded_folder( package, dir ); 675 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( package, full_path ); 676 folder->State = FOLDER_STATE_CREATED; 677 678 return ERROR_SUCCESS; 679 } 680 681 static UINT ACTION_CreateFolders(MSIPACKAGE *package) 682 { 683 MSIQUERY *view; 684 UINT rc; 685 686 if (package->script == SCRIPT_NONE) 687 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateFolders"); 688 689 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view ); 690 if (rc != ERROR_SUCCESS) 691 return ERROR_SUCCESS; 692 693 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); 694 msiobj_release(&view->hdr); 695 return rc; 696 } 697 698 static void remove_persistent_folder( MSIFOLDER *folder ) 699 { 700 FolderList *fl; 701 702 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) 703 { 704 remove_persistent_folder( fl->folder ); 705 } 706 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED) 707 { 708 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED; 709 } 710 } 711 712 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param ) 713 { 714 MSIPACKAGE *package = param; 715 LPCWSTR dir, component, full_path; 716 MSIRECORD *uirow; 717 MSIFOLDER *folder; 718 MSICOMPONENT *comp; 719 720 component = MSI_RecordGetString(row, 2); 721 if (!component) 722 return ERROR_SUCCESS; 723 724 comp = msi_get_loaded_component(package, component); 725 if (!comp) 726 return ERROR_SUCCESS; 727 728 comp->Action = msi_get_component_action( package, comp ); 729 if (comp->Action != INSTALLSTATE_ABSENT) 730 { 731 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 732 return ERROR_SUCCESS; 733 } 734 735 dir = MSI_RecordGetString( row, 1 ); 736 if (!dir) 737 { 738 ERR("Unable to get folder id\n"); 739 return ERROR_SUCCESS; 740 } 741 742 full_path = msi_get_target_folder( package, dir ); 743 if (!full_path) 744 { 745 ERR("Unable to resolve folder %s\n", debugstr_w(dir)); 746 return ERROR_SUCCESS; 747 } 748 TRACE("folder is %s\n", debugstr_w(full_path)); 749 750 uirow = MSI_CreateRecord( 1 ); 751 MSI_RecordSetStringW( uirow, 1, dir ); 752 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 753 msiobj_release( &uirow->hdr ); 754 755 folder = msi_get_loaded_folder( package, dir ); 756 remove_persistent_folder( folder ); 757 return ERROR_SUCCESS; 758 } 759 760 static UINT ACTION_RemoveFolders( MSIPACKAGE *package ) 761 { 762 MSIQUERY *view; 763 UINT rc; 764 765 if (package->script == SCRIPT_NONE) 766 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveFolders"); 767 768 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view ); 769 if (rc != ERROR_SUCCESS) 770 return ERROR_SUCCESS; 771 772 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package ); 773 msiobj_release( &view->hdr ); 774 return rc; 775 } 776 777 static UINT load_component( MSIRECORD *row, LPVOID param ) 778 { 779 MSIPACKAGE *package = param; 780 MSICOMPONENT *comp; 781 782 comp = calloc( 1, sizeof(MSICOMPONENT) ); 783 if (!comp) 784 return ERROR_FUNCTION_FAILED; 785 786 list_add_tail( &package->components, &comp->entry ); 787 788 /* fill in the data */ 789 comp->Component = msi_dup_record_field( row, 1 ); 790 791 TRACE("Loading Component %s\n", debugstr_w(comp->Component)); 792 793 comp->ComponentId = msi_dup_record_field( row, 2 ); 794 comp->Directory = msi_dup_record_field( row, 3 ); 795 comp->Attributes = MSI_RecordGetInteger(row,4); 796 comp->Condition = msi_dup_record_field( row, 5 ); 797 comp->KeyPath = msi_dup_record_field( row, 6 ); 798 799 comp->Installed = INSTALLSTATE_UNKNOWN; 800 comp->Action = INSTALLSTATE_UNKNOWN; 801 comp->ActionRequest = INSTALLSTATE_UNKNOWN; 802 803 comp->assembly = msi_load_assembly( package, comp ); 804 return ERROR_SUCCESS; 805 } 806 807 UINT msi_load_all_components( MSIPACKAGE *package ) 808 { 809 MSIQUERY *view; 810 UINT r; 811 812 if (!list_empty(&package->components)) 813 return ERROR_SUCCESS; 814 815 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Component`", &view ); 816 if (r != ERROR_SUCCESS) 817 return r; 818 819 r = MSI_IterateRecords(view, NULL, load_component, package); 820 msiobj_release(&view->hdr); 821 return r; 822 } 823 824 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp ) 825 { 826 ComponentList *cl; 827 828 cl = malloc( sizeof(*cl) ); 829 if ( !cl ) 830 return ERROR_NOT_ENOUGH_MEMORY; 831 cl->component = comp; 832 list_add_tail( &feature->Components, &cl->entry ); 833 834 return ERROR_SUCCESS; 835 } 836 837 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child ) 838 { 839 FeatureList *fl; 840 841 fl = malloc( sizeof(*fl) ); 842 if ( !fl ) 843 return ERROR_NOT_ENOUGH_MEMORY; 844 fl->feature = child; 845 list_add_tail( &parent->Children, &fl->entry ); 846 847 return ERROR_SUCCESS; 848 } 849 850 struct package_feature 851 { 852 MSIPACKAGE *package; 853 MSIFEATURE *feature; 854 }; 855 856 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) 857 { 858 struct package_feature *package_feature = param; 859 LPCWSTR component; 860 MSICOMPONENT *comp; 861 862 component = MSI_RecordGetString(row,1); 863 864 /* check to see if the component is already loaded */ 865 comp = msi_get_loaded_component( package_feature->package, component ); 866 if (!comp) 867 { 868 WARN("ignoring unknown component %s\n", debugstr_w(component)); 869 return ERROR_SUCCESS; 870 } 871 add_feature_component( package_feature->feature, comp ); 872 comp->Enabled = TRUE; 873 874 return ERROR_SUCCESS; 875 } 876 877 static UINT load_feature(MSIRECORD *row, LPVOID param) 878 { 879 MSIPACKAGE *package = param; 880 MSIFEATURE *feature; 881 MSIQUERY *view; 882 struct package_feature package_feature; 883 UINT rc; 884 885 /* fill in the data */ 886 887 feature = calloc( 1, sizeof(MSIFEATURE) ); 888 if (!feature) 889 return ERROR_NOT_ENOUGH_MEMORY; 890 891 list_init( &feature->Children ); 892 list_init( &feature->Components ); 893 894 feature->Feature = msi_dup_record_field( row, 1 ); 895 896 TRACE("Loading feature %s\n",debugstr_w(feature->Feature)); 897 898 feature->Feature_Parent = msi_dup_record_field( row, 2 ); 899 feature->Title = msi_dup_record_field( row, 3 ); 900 feature->Description = msi_dup_record_field( row, 4 ); 901 902 if (!MSI_RecordIsNull(row,5)) 903 feature->Display = MSI_RecordGetInteger(row,5); 904 905 feature->Level= MSI_RecordGetInteger(row,6); 906 feature->Directory = msi_dup_record_field( row, 7 ); 907 feature->Attributes = MSI_RecordGetInteger(row,8); 908 909 feature->Installed = INSTALLSTATE_UNKNOWN; 910 feature->Action = INSTALLSTATE_UNKNOWN; 911 feature->ActionRequest = INSTALLSTATE_UNKNOWN; 912 913 list_add_tail( &package->features, &feature->entry ); 914 915 /* load feature components */ 916 917 rc = MSI_OpenQuery( package->db, &view, L"SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = '%s'", 918 feature->Feature ); 919 if (rc != ERROR_SUCCESS) 920 return ERROR_SUCCESS; 921 922 package_feature.package = package; 923 package_feature.feature = feature; 924 925 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents, &package_feature); 926 msiobj_release(&view->hdr); 927 return rc; 928 } 929 930 static UINT find_feature_children(MSIRECORD * row, LPVOID param) 931 { 932 MSIPACKAGE *package = param; 933 MSIFEATURE *parent, *child; 934 935 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) ); 936 if (!child) 937 return ERROR_FUNCTION_FAILED; 938 939 if (!child->Feature_Parent) 940 return ERROR_SUCCESS; 941 942 parent = msi_get_loaded_feature( package, child->Feature_Parent ); 943 if (!parent) 944 return ERROR_FUNCTION_FAILED; 945 946 add_feature_child( parent, child ); 947 return ERROR_SUCCESS; 948 } 949 950 UINT msi_load_all_features( MSIPACKAGE *package ) 951 { 952 MSIQUERY *view; 953 UINT r; 954 955 if (!list_empty(&package->features)) 956 return ERROR_SUCCESS; 957 958 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Feature` ORDER BY `Display`", &view ); 959 if (r != ERROR_SUCCESS) 960 return r; 961 962 r = MSI_IterateRecords( view, NULL, load_feature, package ); 963 if (r != ERROR_SUCCESS) 964 { 965 msiobj_release( &view->hdr ); 966 return r; 967 } 968 r = MSI_IterateRecords( view, NULL, find_feature_children, package ); 969 msiobj_release( &view->hdr ); 970 return r; 971 } 972 973 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch) 974 { 975 if (!p) 976 return p; 977 p = wcschr(p, ch); 978 if (!p) 979 return p; 980 *p = 0; 981 return p+1; 982 } 983 984 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file) 985 { 986 MSIQUERY *view = NULL; 987 MSIRECORD *row = NULL; 988 UINT r; 989 990 TRACE("%s\n", debugstr_w(file->File)); 991 992 r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `MsiFileHash` WHERE `File_` = '%s'", file->File); 993 if (r != ERROR_SUCCESS) 994 goto done; 995 996 r = MSI_ViewExecute(view, NULL); 997 if (r != ERROR_SUCCESS) 998 goto done; 999 1000 r = MSI_ViewFetch(view, &row); 1001 if (r != ERROR_SUCCESS) 1002 goto done; 1003 1004 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); 1005 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3); 1006 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4); 1007 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5); 1008 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6); 1009 1010 done: 1011 if (view) msiobj_release(&view->hdr); 1012 if (row) msiobj_release(&row->hdr); 1013 return r; 1014 } 1015 1016 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file ) 1017 { 1018 MSIRECORD *row = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %d", 1019 file->Sequence ); 1020 if (!row) 1021 { 1022 WARN("query failed\n"); 1023 return ERROR_FUNCTION_FAILED; 1024 } 1025 1026 file->disk_id = MSI_RecordGetInteger( row, 1 ); 1027 msiobj_release( &row->hdr ); 1028 return ERROR_SUCCESS; 1029 } 1030 1031 static UINT load_file(MSIRECORD *row, LPVOID param) 1032 { 1033 MSIPACKAGE* package = param; 1034 LPCWSTR component; 1035 MSIFILE *file; 1036 1037 /* fill in the data */ 1038 1039 file = calloc( 1, sizeof(MSIFILE) ); 1040 if (!file) 1041 return ERROR_NOT_ENOUGH_MEMORY; 1042 1043 file->File = msi_dup_record_field( row, 1 ); 1044 1045 component = MSI_RecordGetString( row, 2 ); 1046 file->Component = msi_get_loaded_component( package, component ); 1047 1048 if (!file->Component) 1049 { 1050 WARN("Component not found: %s\n", debugstr_w(component)); 1051 free(file->File); 1052 free(file); 1053 return ERROR_SUCCESS; 1054 } 1055 1056 file->FileName = msi_dup_record_field( row, 3 ); 1057 msi_reduce_to_long_filename( file->FileName ); 1058 1059 file->ShortName = msi_dup_record_field( row, 3 ); 1060 file->LongName = wcsdup( folder_split_path(file->ShortName, '|') ); 1061 1062 file->FileSize = MSI_RecordGetInteger( row, 4 ); 1063 file->Version = msi_dup_record_field( row, 5 ); 1064 file->Language = msi_dup_record_field( row, 6 ); 1065 file->Attributes = MSI_RecordGetInteger( row, 7 ); 1066 file->Sequence = MSI_RecordGetInteger( row, 8 ); 1067 1068 file->state = msifs_invalid; 1069 1070 /* if the compressed bits are not set in the file attributes, 1071 * then read the information from the package word count property 1072 */ 1073 if (package->WordCount & msidbSumInfoSourceTypeAdminImage) 1074 { 1075 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed; 1076 } 1077 else if (file->Attributes & (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded)) 1078 { 1079 file->IsCompressed = TRUE; 1080 } 1081 else if (file->Attributes & msidbFileAttributesNoncompressed) 1082 { 1083 file->IsCompressed = FALSE; 1084 } 1085 else file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed; 1086 1087 load_file_hash(package, file); 1088 load_file_disk_id(package, file); 1089 1090 TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence); 1091 1092 list_add_tail( &package->files, &file->entry ); 1093 return ERROR_SUCCESS; 1094 } 1095 1096 static UINT load_all_files(MSIPACKAGE *package) 1097 { 1098 MSIQUERY *view; 1099 UINT rc; 1100 1101 if (!list_empty(&package->files)) 1102 return ERROR_SUCCESS; 1103 1104 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `File` ORDER BY `Sequence`", &view); 1105 if (rc != ERROR_SUCCESS) 1106 return ERROR_SUCCESS; 1107 1108 rc = MSI_IterateRecords(view, NULL, load_file, package); 1109 msiobj_release(&view->hdr); 1110 return rc; 1111 } 1112 1113 static UINT load_media( MSIRECORD *row, LPVOID param ) 1114 { 1115 MSIPACKAGE *package = param; 1116 UINT disk_id = MSI_RecordGetInteger( row, 1 ); 1117 const WCHAR *cabinet = MSI_RecordGetString( row, 4 ); 1118 1119 /* FIXME: load external cabinets and directory sources too */ 1120 if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID) 1121 return ERROR_SUCCESS; 1122 1123 return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet ); 1124 } 1125 1126 static UINT load_all_media( MSIPACKAGE *package ) 1127 { 1128 MSIQUERY *view; 1129 UINT r; 1130 1131 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Media` ORDER BY `DiskId`", &view ); 1132 if (r != ERROR_SUCCESS) 1133 return ERROR_SUCCESS; 1134 1135 r = MSI_IterateRecords( view, NULL, load_media, package ); 1136 msiobj_release( &view->hdr ); 1137 return r; 1138 } 1139 1140 static UINT load_patch_disk_id( MSIPACKAGE *package, MSIFILEPATCH *patch ) 1141 { 1142 MSIRECORD *rec = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %u", 1143 patch->Sequence ); 1144 if (!rec) 1145 { 1146 WARN("query failed\n"); 1147 return ERROR_FUNCTION_FAILED; 1148 } 1149 1150 patch->disk_id = MSI_RecordGetInteger( rec, 1 ); 1151 msiobj_release( &rec->hdr ); 1152 return ERROR_SUCCESS; 1153 } 1154 1155 static UINT load_patch(MSIRECORD *row, LPVOID param) 1156 { 1157 MSIPACKAGE *package = param; 1158 MSIFILEPATCH *patch; 1159 const WCHAR *file_key; 1160 1161 patch = calloc( 1, sizeof(MSIFILEPATCH) ); 1162 if (!patch) 1163 return ERROR_NOT_ENOUGH_MEMORY; 1164 1165 file_key = MSI_RecordGetString( row, 1 ); 1166 patch->File = msi_get_loaded_file( package, file_key ); 1167 if (!patch->File) 1168 { 1169 ERR("Failed to find target for patch in File table\n"); 1170 free(patch); 1171 return ERROR_FUNCTION_FAILED; 1172 } 1173 1174 patch->Sequence = MSI_RecordGetInteger( row, 2 ); 1175 patch->PatchSize = MSI_RecordGetInteger( row, 3 ); 1176 patch->Attributes = MSI_RecordGetInteger( row, 4 ); 1177 1178 /* FIXME: 1179 * Header field - for patch validation. 1180 * _StreamRef - External key into MsiPatchHeaders (instead of the header field) 1181 */ 1182 1183 load_patch_disk_id( package, patch ); 1184 1185 TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence); 1186 1187 list_add_tail( &package->filepatches, &patch->entry ); 1188 1189 return ERROR_SUCCESS; 1190 } 1191 1192 static UINT load_all_patches(MSIPACKAGE *package) 1193 { 1194 MSIQUERY *view; 1195 UINT rc; 1196 1197 if (!list_empty(&package->filepatches)) 1198 return ERROR_SUCCESS; 1199 1200 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Patch` ORDER BY `Sequence`", &view); 1201 if (rc != ERROR_SUCCESS) 1202 return ERROR_SUCCESS; 1203 1204 rc = MSI_IterateRecords(view, NULL, load_patch, package); 1205 msiobj_release(&view->hdr); 1206 return rc; 1207 } 1208 1209 static UINT iterate_patched_component( MSIRECORD *row, LPVOID param ) 1210 { 1211 MSIPACKAGE *package = param; 1212 const WCHAR *name; 1213 MSICOMPONENT *c; 1214 1215 name = MSI_RecordGetString( row, 1 ); 1216 TRACE( "found patched component: %s\n", wine_dbgstr_w(name) ); 1217 c = msi_get_loaded_component( package, name ); 1218 if (!c) 1219 return ERROR_SUCCESS; 1220 1221 c->updated = 1; 1222 if (!wcscmp( MSI_RecordGetString( row, 2 ), L"INSERT" )) 1223 c->added = 1; 1224 return ERROR_SUCCESS; 1225 } 1226 1227 static void mark_patched_components( MSIPACKAGE *package ) 1228 { 1229 static const WCHAR select[] = L"SELECT `Row`, `Column` FROM `_TransformView` WHERE `Table`='Component'"; 1230 MSIQUERY *q; 1231 UINT r; 1232 1233 r = MSI_OpenQuery( package->db, &q, select ); 1234 if (r != ERROR_SUCCESS) 1235 return; 1236 1237 MSI_IterateRecords( q, NULL, iterate_patched_component, package ); 1238 msiobj_release( &q->hdr ); 1239 1240 while (1) 1241 { 1242 r = MSI_OpenQuery( package->db, &q, L"ALTER TABLE `_TransformView` FREE" ); 1243 if (r != ERROR_SUCCESS) 1244 return; 1245 r = MSI_ViewExecute( q, NULL ); 1246 msiobj_release( &q->hdr ); 1247 if (r != ERROR_SUCCESS) 1248 return; 1249 } 1250 } 1251 1252 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder ) 1253 { 1254 MSIQUERY *view; 1255 1256 folder->persistent = FALSE; 1257 if (!MSI_OpenQuery( package->db, &view, L"SELECT * FROM `CreateFolder` WHERE `Directory_` = '%s'", 1258 folder->Directory )) 1259 { 1260 if (!MSI_ViewExecute( view, NULL )) 1261 { 1262 MSIRECORD *rec; 1263 if (!MSI_ViewFetch( view, &rec )) 1264 { 1265 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory)); 1266 folder->persistent = TRUE; 1267 msiobj_release( &rec->hdr ); 1268 } 1269 } 1270 msiobj_release( &view->hdr ); 1271 } 1272 return ERROR_SUCCESS; 1273 } 1274 1275 static UINT load_folder( MSIRECORD *row, LPVOID param ) 1276 { 1277 MSIPACKAGE *package = param; 1278 static WCHAR szEmpty[] = L""; 1279 LPWSTR p, tgt_short, tgt_long, src_short, src_long; 1280 MSIFOLDER *folder; 1281 1282 if (!(folder = calloc( 1, sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY; 1283 list_init( &folder->children ); 1284 folder->Directory = msi_dup_record_field( row, 1 ); 1285 folder->Parent = msi_dup_record_field( row, 2 ); 1286 p = msi_dup_record_field(row, 3); 1287 1288 TRACE("%s\n", debugstr_w(folder->Directory)); 1289 1290 /* split src and target dir */ 1291 tgt_short = p; 1292 src_short = folder_split_path( p, ':' ); 1293 1294 /* split the long and short paths */ 1295 tgt_long = folder_split_path( tgt_short, '|' ); 1296 src_long = folder_split_path( src_short, '|' ); 1297 1298 /* check for no-op dirs */ 1299 if (tgt_short && !wcscmp( L".", tgt_short )) 1300 tgt_short = szEmpty; 1301 if (src_short && !wcscmp( L".", src_short )) 1302 src_short = szEmpty; 1303 1304 if (!tgt_long) 1305 tgt_long = tgt_short; 1306 1307 if (!src_short) { 1308 src_short = tgt_short; 1309 src_long = tgt_long; 1310 } 1311 1312 if (!src_long) 1313 src_long = src_short; 1314 1315 /* FIXME: use the target short path too */ 1316 folder->TargetDefault = wcsdup(tgt_long); 1317 folder->SourceShortPath = wcsdup(src_short); 1318 folder->SourceLongPath = wcsdup(src_long); 1319 free(p); 1320 1321 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault )); 1322 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath )); 1323 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath )); 1324 1325 load_folder_persistence( package, folder ); 1326 1327 list_add_tail( &package->folders, &folder->entry ); 1328 return ERROR_SUCCESS; 1329 } 1330 1331 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child ) 1332 { 1333 FolderList *fl; 1334 1335 if (!(fl = malloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY; 1336 fl->folder = child; 1337 list_add_tail( &parent->children, &fl->entry ); 1338 return ERROR_SUCCESS; 1339 } 1340 1341 static UINT find_folder_children( MSIRECORD *row, LPVOID param ) 1342 { 1343 MSIPACKAGE *package = param; 1344 MSIFOLDER *parent, *child; 1345 1346 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) ))) 1347 return ERROR_FUNCTION_FAILED; 1348 1349 if (!child->Parent) return ERROR_SUCCESS; 1350 1351 if (!(parent = msi_get_loaded_folder( package, child->Parent ))) 1352 return ERROR_FUNCTION_FAILED; 1353 1354 return add_folder_child( parent, child ); 1355 } 1356 1357 static UINT load_all_folders( MSIPACKAGE *package ) 1358 { 1359 MSIQUERY *view; 1360 UINT r; 1361 1362 if (!list_empty(&package->folders)) 1363 return ERROR_SUCCESS; 1364 1365 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Directory`", &view ); 1366 if (r != ERROR_SUCCESS) 1367 return r; 1368 1369 r = MSI_IterateRecords( view, NULL, load_folder, package ); 1370 if (r != ERROR_SUCCESS) 1371 { 1372 msiobj_release( &view->hdr ); 1373 return r; 1374 } 1375 r = MSI_IterateRecords( view, NULL, find_folder_children, package ); 1376 msiobj_release( &view->hdr ); 1377 return r; 1378 } 1379 1380 static UINT ACTION_CostInitialize(MSIPACKAGE *package) 1381 { 1382 msi_set_property( package->db, L"CostingComplete", L"0", -1 ); 1383 msi_set_property( package->db, L"ROOTDRIVE", L"C:\\", -1 ); 1384 1385 load_all_folders( package ); 1386 msi_load_all_components( package ); 1387 msi_load_all_features( package ); 1388 load_all_files( package ); 1389 load_all_patches( package ); 1390 mark_patched_components( package ); 1391 load_all_media( package ); 1392 1393 return ERROR_SUCCESS; 1394 } 1395 1396 static UINT execute_script( MSIPACKAGE *package, UINT script ) 1397 { 1398 UINT i, rc = ERROR_SUCCESS; 1399 1400 TRACE("executing script %u\n", script); 1401 1402 package->script = script; 1403 1404 if (script == SCRIPT_ROLLBACK) 1405 { 1406 for (i = package->script_actions_count[script]; i > 0; i--) 1407 { 1408 rc = ACTION_PerformAction(package, package->script_actions[script][i-1]); 1409 if (rc != ERROR_SUCCESS) 1410 { 1411 ERR("Execution of script %i halted; action %s returned %u\n", 1412 script, debugstr_w(package->script_actions[script][i-1]), rc); 1413 break; 1414 } 1415 } 1416 } 1417 else 1418 { 1419 for (i = 0; i < package->script_actions_count[script]; i++) 1420 { 1421 rc = ACTION_PerformAction(package, package->script_actions[script][i]); 1422 if (rc != ERROR_SUCCESS) 1423 { 1424 ERR("Execution of script %i halted; action %s returned %u\n", 1425 script, debugstr_w(package->script_actions[script][i]), rc); 1426 break; 1427 } 1428 } 1429 } 1430 1431 package->script = SCRIPT_NONE; 1432 1433 msi_free_action_script(package, script); 1434 return rc; 1435 } 1436 1437 static UINT ACTION_FileCost(MSIPACKAGE *package) 1438 { 1439 return ERROR_SUCCESS; 1440 } 1441 1442 static void get_client_counts( MSIPACKAGE *package ) 1443 { 1444 MSICOMPONENT *comp; 1445 HKEY hkey; 1446 1447 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 1448 { 1449 if (!comp->ComponentId) continue; 1450 1451 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE ) && 1452 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE )) 1453 { 1454 comp->num_clients = 0; 1455 continue; 1456 } 1457 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients, 1458 NULL, NULL, NULL, NULL ); 1459 RegCloseKey( hkey ); 1460 } 1461 } 1462 1463 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package) 1464 { 1465 MSICOMPONENT *comp; 1466 UINT r; 1467 1468 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) 1469 { 1470 if (!comp->ComponentId) continue; 1471 1472 r = MsiQueryComponentStateW( package->ProductCode, NULL, 1473 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId, 1474 &comp->Installed ); 1475 if (r == ERROR_SUCCESS) continue; 1476 1477 r = MsiQueryComponentStateW( package->ProductCode, NULL, 1478 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId, 1479 &comp->Installed ); 1480 if (r == ERROR_SUCCESS) continue; 1481 1482 r = MsiQueryComponentStateW( package->ProductCode, NULL, 1483 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId, 1484 &comp->Installed ); 1485 if (r == ERROR_SUCCESS) continue; 1486 1487 comp->Installed = INSTALLSTATE_ABSENT; 1488 } 1489 } 1490 1491 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package) 1492 { 1493 MSIFEATURE *feature; 1494 1495 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1496 { 1497 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature ); 1498 1499 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG) 1500 feature->Installed = INSTALLSTATE_ABSENT; 1501 else 1502 feature->Installed = state; 1503 } 1504 } 1505 1506 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level ) 1507 { 1508 return (feature->Level > 0 && feature->Level <= level); 1509 } 1510 1511 static BOOL process_state_property(MSIPACKAGE* package, int level, 1512 LPCWSTR property, INSTALLSTATE state) 1513 { 1514 LPWSTR override; 1515 MSIFEATURE *feature; 1516 BOOL remove = !wcscmp(property, L"REMOVE"); 1517 BOOL reinstall = !wcscmp(property, L"REINSTALL"); 1518 1519 override = msi_dup_property( package->db, property ); 1520 if (!override) 1521 return FALSE; 1522 1523 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1524 { 1525 if (feature->Level <= 0) 1526 continue; 1527 1528 if (reinstall) 1529 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : feature->Installed); 1530 else if (remove) 1531 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : INSTALLSTATE_ABSENT); 1532 1533 if (!wcsicmp( override, L"ALL" )) 1534 { 1535 feature->Action = state; 1536 feature->ActionRequest = state; 1537 } 1538 else 1539 { 1540 LPWSTR ptr = override; 1541 LPWSTR ptr2 = wcschr(override,','); 1542 1543 while (ptr) 1544 { 1545 int len = ptr2 - ptr; 1546 1547 if ((ptr2 && lstrlenW(feature->Feature) == len && !wcsncmp(ptr, feature->Feature, len)) 1548 || (!ptr2 && !wcscmp(ptr, feature->Feature))) 1549 { 1550 feature->Action = state; 1551 feature->ActionRequest = state; 1552 break; 1553 } 1554 if (ptr2) 1555 { 1556 ptr=ptr2+1; 1557 ptr2 = wcschr(ptr,','); 1558 } 1559 else 1560 break; 1561 } 1562 } 1563 } 1564 free(override); 1565 return TRUE; 1566 } 1567 1568 static BOOL process_overrides( MSIPACKAGE *package, int level ) 1569 { 1570 BOOL ret = FALSE; 1571 1572 /* all these activation/deactivation things happen in order and things 1573 * later on the list override things earlier on the list. 1574 * 1575 * 0 INSTALLLEVEL processing 1576 * 1 ADDLOCAL 1577 * 2 REMOVE 1578 * 3 ADDSOURCE 1579 * 4 ADDDEFAULT 1580 * 5 REINSTALL 1581 * 6 ADVERTISE 1582 * 7 COMPADDLOCAL 1583 * 8 COMPADDSOURCE 1584 * 9 FILEADDLOCAL 1585 * 10 FILEADDSOURCE 1586 * 11 FILEADDDEFAULT 1587 */ 1588 ret |= process_state_property( package, level, L"ADDLOCAL", INSTALLSTATE_LOCAL ); 1589 ret |= process_state_property( package, level, L"REMOVE", INSTALLSTATE_ABSENT ); 1590 ret |= process_state_property( package, level, L"ADDSOURCE", INSTALLSTATE_SOURCE ); 1591 ret |= process_state_property( package, level, L"REINSTALL", INSTALLSTATE_UNKNOWN ); 1592 ret |= process_state_property( package, level, L"ADVERTISE", INSTALLSTATE_ADVERTISED ); 1593 1594 if (ret) 1595 msi_set_property( package->db, L"Preselected", L"1", -1 ); 1596 1597 return ret; 1598 } 1599 1600 static void disable_children( MSIFEATURE *feature, int level ) 1601 { 1602 FeatureList *fl; 1603 1604 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) 1605 { 1606 if (!is_feature_selected( feature, level )) 1607 { 1608 TRACE("child %s (level %d request %d) follows disabled parent %s (level %d request %d)\n", 1609 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest, 1610 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest); 1611 1612 fl->feature->Level = feature->Level; 1613 fl->feature->Action = INSTALLSTATE_UNKNOWN; 1614 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN; 1615 } 1616 disable_children( fl->feature, level ); 1617 } 1618 } 1619 1620 static void follow_parent( MSIFEATURE *feature ) 1621 { 1622 FeatureList *fl; 1623 1624 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) 1625 { 1626 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent) 1627 { 1628 TRACE("child %s (level %d request %d) follows parent %s (level %d request %d)\n", 1629 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest, 1630 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest); 1631 1632 fl->feature->Action = feature->Action; 1633 fl->feature->ActionRequest = feature->ActionRequest; 1634 } 1635 follow_parent( fl->feature ); 1636 } 1637 } 1638 1639 UINT MSI_SetFeatureStates(MSIPACKAGE *package) 1640 { 1641 int level; 1642 MSICOMPONENT* component; 1643 MSIFEATURE *feature; 1644 1645 TRACE("Checking Install Level\n"); 1646 1647 level = msi_get_property_int(package->db, L"INSTALLLEVEL", 1); 1648 1649 if (msi_get_property_int( package->db, L"Preselected", 0 )) 1650 { 1651 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1652 { 1653 if (!is_feature_selected( feature, level )) continue; 1654 1655 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) 1656 { 1657 if (feature->Installed == INSTALLSTATE_ABSENT) 1658 { 1659 feature->Action = INSTALLSTATE_UNKNOWN; 1660 feature->ActionRequest = INSTALLSTATE_UNKNOWN; 1661 } 1662 else 1663 { 1664 feature->Action = feature->Installed; 1665 feature->ActionRequest = feature->Installed; 1666 } 1667 } 1668 } 1669 } 1670 else if (!msi_get_property_int( package->db, L"Installed", 0 )) 1671 { 1672 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1673 { 1674 if (!is_feature_selected( feature, level )) continue; 1675 1676 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) 1677 { 1678 if (feature->Attributes & msidbFeatureAttributesFavorSource) 1679 { 1680 feature->Action = INSTALLSTATE_SOURCE; 1681 feature->ActionRequest = INSTALLSTATE_SOURCE; 1682 } 1683 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) 1684 { 1685 feature->Action = INSTALLSTATE_ADVERTISED; 1686 feature->ActionRequest = INSTALLSTATE_ADVERTISED; 1687 } 1688 else 1689 { 1690 feature->Action = INSTALLSTATE_LOCAL; 1691 feature->ActionRequest = INSTALLSTATE_LOCAL; 1692 } 1693 } 1694 } 1695 } 1696 else 1697 { 1698 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1699 { 1700 ComponentList *cl; 1701 MSIFEATURE *cur; 1702 1703 if (!is_feature_selected( feature, level )) continue; 1704 if (feature->ActionRequest != INSTALLSTATE_UNKNOWN) continue; 1705 1706 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 1707 { 1708 if (!cl->component->updated && !cl->component->added) 1709 continue; 1710 1711 cur = feature; 1712 while (cur) 1713 { 1714 if (cur->ActionRequest != INSTALLSTATE_UNKNOWN) 1715 break; 1716 1717 if (cur->Installed != INSTALLSTATE_ABSENT) 1718 { 1719 cur->Action = cur->Installed; 1720 cur->ActionRequest = cur->Installed; 1721 } 1722 else if (!cl->component->added) 1723 { 1724 break; 1725 } 1726 else if (cur->Attributes & msidbFeatureAttributesFavorSource) 1727 { 1728 cur->Action = INSTALLSTATE_SOURCE; 1729 cur->ActionRequest = INSTALLSTATE_SOURCE; 1730 } 1731 else if (cur->Attributes & msidbFeatureAttributesFavorAdvertise) 1732 { 1733 cur->Action = INSTALLSTATE_ADVERTISED; 1734 cur->ActionRequest = INSTALLSTATE_ADVERTISED; 1735 } 1736 else 1737 { 1738 cur->Action = INSTALLSTATE_LOCAL; 1739 cur->ActionRequest = INSTALLSTATE_LOCAL; 1740 } 1741 1742 if (!cur->Feature_Parent) 1743 break; 1744 cur = msi_get_loaded_feature(package, cur->Feature_Parent); 1745 } 1746 } 1747 } 1748 } 1749 1750 /* disable child features of unselected parent or follow parent */ 1751 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1752 { 1753 if (feature->Feature_Parent) continue; 1754 disable_children( feature, level ); 1755 follow_parent( feature ); 1756 } 1757 1758 /* now we want to set component state based based on feature state */ 1759 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 1760 { 1761 ComponentList *cl; 1762 1763 TRACE("examining feature %s (level %d installed %d request %d action %d)\n", 1764 debugstr_w(feature->Feature), feature->Level, feature->Installed, 1765 feature->ActionRequest, feature->Action); 1766 1767 /* features with components that have compressed files are made local */ 1768 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 1769 { 1770 if (cl->component->ForceLocalState && 1771 feature->ActionRequest == INSTALLSTATE_SOURCE) 1772 { 1773 feature->Action = INSTALLSTATE_LOCAL; 1774 feature->ActionRequest = INSTALLSTATE_LOCAL; 1775 break; 1776 } 1777 } 1778 1779 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 1780 { 1781 component = cl->component; 1782 1783 switch (feature->ActionRequest) 1784 { 1785 case INSTALLSTATE_ABSENT: 1786 component->anyAbsent = 1; 1787 break; 1788 case INSTALLSTATE_ADVERTISED: 1789 component->hasAdvertisedFeature = 1; 1790 break; 1791 case INSTALLSTATE_SOURCE: 1792 component->hasSourceFeature = 1; 1793 break; 1794 case INSTALLSTATE_LOCAL: 1795 component->hasLocalFeature = 1; 1796 break; 1797 case INSTALLSTATE_DEFAULT: 1798 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) 1799 component->hasAdvertisedFeature = 1; 1800 else if (feature->Attributes & msidbFeatureAttributesFavorSource) 1801 component->hasSourceFeature = 1; 1802 else 1803 component->hasLocalFeature = 1; 1804 break; 1805 case INSTALLSTATE_UNKNOWN: 1806 if (feature->Installed == INSTALLSTATE_ADVERTISED) 1807 component->hasAdvertisedFeature = 1; 1808 if (feature->Installed == INSTALLSTATE_SOURCE) 1809 component->hasSourceFeature = 1; 1810 if (feature->Installed == INSTALLSTATE_LOCAL) 1811 component->hasLocalFeature = 1; 1812 break; 1813 default: 1814 break; 1815 } 1816 } 1817 } 1818 1819 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) 1820 { 1821 /* check if it's local or source */ 1822 if (!(component->Attributes & msidbComponentAttributesOptional) && 1823 (component->hasLocalFeature || component->hasSourceFeature)) 1824 { 1825 if ((component->Attributes & msidbComponentAttributesSourceOnly) && 1826 !component->ForceLocalState) 1827 { 1828 component->Action = INSTALLSTATE_SOURCE; 1829 component->ActionRequest = INSTALLSTATE_SOURCE; 1830 } 1831 else 1832 { 1833 component->Action = INSTALLSTATE_LOCAL; 1834 component->ActionRequest = INSTALLSTATE_LOCAL; 1835 } 1836 continue; 1837 } 1838 1839 /* if any feature is local, the component must be local too */ 1840 if (component->hasLocalFeature) 1841 { 1842 component->Action = INSTALLSTATE_LOCAL; 1843 component->ActionRequest = INSTALLSTATE_LOCAL; 1844 continue; 1845 } 1846 if (component->hasSourceFeature) 1847 { 1848 component->Action = INSTALLSTATE_SOURCE; 1849 component->ActionRequest = INSTALLSTATE_SOURCE; 1850 continue; 1851 } 1852 if (component->hasAdvertisedFeature) 1853 { 1854 component->Action = INSTALLSTATE_ADVERTISED; 1855 component->ActionRequest = INSTALLSTATE_ADVERTISED; 1856 continue; 1857 } 1858 TRACE("nobody wants component %s\n", debugstr_w(component->Component)); 1859 if (component->anyAbsent && component->ComponentId) 1860 { 1861 component->Action = INSTALLSTATE_ABSENT; 1862 component->ActionRequest = INSTALLSTATE_ABSENT; 1863 } 1864 } 1865 1866 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) 1867 { 1868 if (component->ActionRequest == INSTALLSTATE_DEFAULT) 1869 { 1870 TRACE("%s was default, setting to local\n", debugstr_w(component->Component)); 1871 component->Action = INSTALLSTATE_LOCAL; 1872 component->ActionRequest = INSTALLSTATE_LOCAL; 1873 } 1874 1875 if (component->ActionRequest == INSTALLSTATE_SOURCE && 1876 component->Installed == INSTALLSTATE_SOURCE && 1877 component->hasSourceFeature) 1878 { 1879 component->Action = INSTALLSTATE_UNKNOWN; 1880 component->ActionRequest = INSTALLSTATE_UNKNOWN; 1881 } 1882 1883 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE) 1884 component->num_clients++; 1885 else if (component->Action == INSTALLSTATE_ABSENT) 1886 { 1887 component->num_clients--; 1888 1889 if (component->num_clients > 0) 1890 { 1891 TRACE("multiple clients uses %s - disallowing uninstallation\n", debugstr_w(component->Component)); 1892 component->Action = INSTALLSTATE_UNKNOWN; 1893 } 1894 } 1895 1896 TRACE("component %s (installed %d request %d action %d)\n", 1897 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action); 1898 } 1899 1900 return ERROR_SUCCESS; 1901 } 1902 1903 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) 1904 { 1905 MSIPACKAGE *package = param; 1906 LPCWSTR name; 1907 MSIFEATURE *feature; 1908 1909 name = MSI_RecordGetString( row, 1 ); 1910 1911 feature = msi_get_loaded_feature( package, name ); 1912 if (!feature) 1913 ERR("FAILED to find loaded feature %s\n",debugstr_w(name)); 1914 else 1915 { 1916 LPCWSTR Condition; 1917 Condition = MSI_RecordGetString(row,3); 1918 1919 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) 1920 { 1921 int level = MSI_RecordGetInteger(row,2); 1922 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level); 1923 feature->Level = level; 1924 } 1925 } 1926 return ERROR_SUCCESS; 1927 } 1928 1929 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version ) 1930 { 1931 DWORD ms, ls; 1932 1933 msi_parse_version_string( version, &ms, &ls ); 1934 1935 if (fi->dwFileVersionMS > ms) return 1; 1936 else if (fi->dwFileVersionMS < ms) return -1; 1937 else if (fi->dwFileVersionLS > ls) return 1; 1938 else if (fi->dwFileVersionLS < ls) return -1; 1939 return 0; 1940 } 1941 1942 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 ) 1943 { 1944 DWORD ms1, ms2; 1945 1946 msi_parse_version_string( ver1, &ms1, NULL ); 1947 msi_parse_version_string( ver2, &ms2, NULL ); 1948 1949 if (ms1 > ms2) return 1; 1950 else if (ms1 < ms2) return -1; 1951 return 0; 1952 } 1953 1954 static WCHAR *create_temp_dir( MSIDATABASE *db ) 1955 { 1956 static UINT id; 1957 WCHAR *ret; 1958 1959 if (!db->tempfolder) 1960 { 1961 WCHAR tmp[MAX_PATH]; 1962 DWORD len = ARRAY_SIZE( tmp ); 1963 1964 if (msi_get_property( db, L"TempFolder", tmp, &len ) || 1965 GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY) 1966 { 1967 GetTempPathW( MAX_PATH, tmp ); 1968 } 1969 if (!(db->tempfolder = wcsdup( tmp ))) return NULL; 1970 } 1971 1972 if ((ret = malloc( (wcslen( db->tempfolder ) + 20) * sizeof(WCHAR) ))) 1973 { 1974 for (;;) 1975 { 1976 if (!GetTempFileNameW( db->tempfolder, L"msi", ++id, ret )) 1977 { 1978 free( ret ); 1979 return NULL; 1980 } 1981 if (CreateDirectoryW( ret, NULL )) break; 1982 } 1983 } 1984 1985 return ret; 1986 } 1987 1988 /* 1989 * msi_build_directory_name() 1990 * 1991 * This function is to save messing round with directory names 1992 * It handles adding backslashes between path segments, 1993 * and can add \ at the end of the directory name if told to. 1994 * 1995 * It takes a variable number of arguments. 1996 * It always allocates a new string for the result, so make sure 1997 * to free the return value when finished with it. 1998 * 1999 * The first arg is the number of path segments that follow. 2000 * The arguments following count are a list of path segments. 2001 * A path segment may be NULL. 2002 * 2003 * Path segments will be added with a \ separating them. 2004 * A \ will not be added after the last segment, however if the 2005 * last segment is NULL, then the last character will be a \ 2006 */ 2007 WCHAR * WINAPIV msi_build_directory_name( DWORD count, ... ) 2008 { 2009 DWORD sz = 1, i; 2010 WCHAR *dir; 2011 va_list va; 2012 2013 va_start( va, count ); 2014 for (i = 0; i < count; i++) 2015 { 2016 const WCHAR *str = va_arg( va, const WCHAR * ); 2017 if (str) sz += lstrlenW( str ) + 1; 2018 } 2019 va_end( va ); 2020 2021 dir = malloc( sz * sizeof(WCHAR) ); 2022 dir[0] = 0; 2023 2024 va_start( va, count ); 2025 for (i = 0; i < count; i++) 2026 { 2027 const WCHAR *str = va_arg( va, const WCHAR * ); 2028 if (!str) continue; 2029 lstrcatW( dir, str ); 2030 if ( i + 1 != count && dir[0] && dir[lstrlenW( dir ) - 1] != '\\') lstrcatW( dir, L"\\" ); 2031 } 2032 va_end( va ); 2033 return dir; 2034 } 2035 2036 BOOL msi_is_global_assembly( MSICOMPONENT *comp ) 2037 { 2038 return comp->assembly && !comp->assembly->application; 2039 } 2040 2041 static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) 2042 { 2043 free( file->TargetPath ); 2044 if (msi_is_global_assembly( file->Component )) 2045 { 2046 MSIASSEMBLY *assembly = file->Component->assembly; 2047 2048 if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db ); 2049 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName ); 2050 } 2051 else 2052 { 2053 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory ); 2054 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName ); 2055 } 2056 2057 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath)); 2058 } 2059 2060 static UINT calculate_file_cost( MSIPACKAGE *package ) 2061 { 2062 VS_FIXEDFILEINFO *file_version; 2063 WCHAR *font_version; 2064 MSIFILE *file; 2065 2066 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 2067 { 2068 MSICOMPONENT *comp = file->Component; 2069 DWORD file_size; 2070 2071 if (!comp->Enabled) continue; 2072 2073 if (file->IsCompressed) 2074 comp->ForceLocalState = TRUE; 2075 2076 set_target_path( package, file ); 2077 2078 if (msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES) 2079 { 2080 comp->cost += cost_from_size( file->FileSize ); 2081 continue; 2082 } 2083 file_size = msi_get_disk_file_size( package, file->TargetPath ); 2084 TRACE("%s (size %lu)\n", debugstr_w(file->TargetPath), file_size); 2085 2086 if (file->Version) 2087 { 2088 if ((file_version = msi_get_disk_file_version( package, file->TargetPath ))) 2089 { 2090 if (msi_compare_file_versions( file_version, file->Version ) < 0) 2091 { 2092 comp->cost += cost_from_size( file->FileSize - file_size ); 2093 } 2094 free( file_version ); 2095 continue; 2096 } 2097 else if ((font_version = msi_get_font_file_version( package, file->TargetPath ))) 2098 { 2099 if (msi_compare_font_versions( font_version, file->Version ) < 0) 2100 { 2101 comp->cost += cost_from_size( file->FileSize - file_size ); 2102 } 2103 free( font_version ); 2104 continue; 2105 } 2106 } 2107 if (file_size != file->FileSize) 2108 { 2109 comp->cost += cost_from_size( file->FileSize - file_size ); 2110 } 2111 } 2112 2113 return ERROR_SUCCESS; 2114 } 2115 2116 WCHAR *msi_normalize_path( const WCHAR *in ) 2117 { 2118 const WCHAR *p = in; 2119 WCHAR *q, *ret; 2120 int n, len = lstrlenW( in ) + 2; 2121 2122 if (!(q = ret = malloc( len * sizeof(WCHAR) ))) return NULL; 2123 2124 len = 0; 2125 while (1) 2126 { 2127 /* copy until the end of the string or a space */ 2128 while (*p != ' ' && (*q = *p)) 2129 { 2130 p++, len++; 2131 /* reduce many backslashes to one */ 2132 if (*p != '\\' || *q != '\\') 2133 q++; 2134 } 2135 2136 /* quit at the end of the string */ 2137 if (!*p) 2138 break; 2139 2140 /* count the number of spaces */ 2141 n = 0; 2142 while (p[n] == ' ') 2143 n++; 2144 2145 /* if it's leading or trailing space, skip it */ 2146 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' ) 2147 p += n; 2148 else /* copy n spaces */ 2149 while (n && (*q++ = *p++)) n--; 2150 } 2151 while (q - ret > 0 && q[-1] == ' ') q--; 2152 if (q - ret > 0 && q[-1] != '\\') 2153 { 2154 q[0] = '\\'; 2155 q[1] = 0; 2156 } 2157 return ret; 2158 } 2159 2160 static WCHAR *get_install_location( MSIPACKAGE *package ) 2161 { 2162 HKEY hkey; 2163 WCHAR *path; 2164 2165 if (!package->ProductCode) return NULL; 2166 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE )) return NULL; 2167 if ((path = msi_reg_get_val_str( hkey, L"InstallLocation" )) && !path[0]) 2168 { 2169 free( path ); 2170 path = NULL; 2171 } 2172 RegCloseKey( hkey ); 2173 return path; 2174 } 2175 2176 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop ) 2177 { 2178 FolderList *fl; 2179 MSIFOLDER *folder, *parent, *child; 2180 WCHAR *path, *normalized_path; 2181 2182 TRACE("resolving %s\n", debugstr_w(name)); 2183 2184 if (!(folder = msi_get_loaded_folder( package, name ))) return; 2185 2186 if (!wcscmp( folder->Directory, L"TARGETDIR" )) /* special resolving for target root dir */ 2187 { 2188 if (!(path = get_install_location( package )) && 2189 (!load_prop || !(path = msi_dup_property( package->db, L"TARGETDIR" )))) 2190 { 2191 path = msi_dup_property( package->db, L"ROOTDRIVE" ); 2192 } 2193 } 2194 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory ))) 2195 { 2196 if (folder->Parent && wcscmp( folder->Directory, folder->Parent )) 2197 { 2198 parent = msi_get_loaded_folder( package, folder->Parent ); 2199 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL ); 2200 } 2201 else 2202 path = msi_build_directory_name( 2, folder->TargetDefault, NULL ); 2203 } 2204 2205 normalized_path = msi_normalize_path( path ); 2206 msi_set_property( package->db, folder->Directory, normalized_path, -1 ); 2207 free( path ); 2208 2209 free( folder->ResolvedTarget ); 2210 folder->ResolvedTarget = normalized_path; 2211 2212 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) 2213 { 2214 child = fl->folder; 2215 msi_resolve_target_folder( package, child->Directory, load_prop ); 2216 } 2217 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget)); 2218 } 2219 2220 static ULONGLONG get_volume_space_required( MSIPACKAGE *package ) 2221 { 2222 MSICOMPONENT *comp; 2223 ULONGLONG ret = 0; 2224 2225 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 2226 { 2227 if (comp->Action == INSTALLSTATE_LOCAL) ret += comp->cost; 2228 } 2229 return ret; 2230 } 2231 2232 static UINT ACTION_CostFinalize(MSIPACKAGE *package) 2233 { 2234 MSICOMPONENT *comp; 2235 MSIQUERY *view; 2236 WCHAR *level, *primary_key, *primary_folder; 2237 UINT rc; 2238 2239 TRACE("Building directory properties\n"); 2240 msi_resolve_target_folder( package, L"TARGETDIR", TRUE ); 2241 2242 TRACE("Evaluating component conditions\n"); 2243 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 2244 { 2245 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE) 2246 { 2247 TRACE("Disabling component %s\n", debugstr_w(comp->Component)); 2248 comp->Enabled = FALSE; 2249 } 2250 else 2251 comp->Enabled = TRUE; 2252 } 2253 get_client_counts( package ); 2254 2255 /* read components states from the registry */ 2256 ACTION_GetComponentInstallStates(package); 2257 ACTION_GetFeatureInstallStates(package); 2258 2259 if (!process_overrides( package, msi_get_property_int( package->db, L"INSTALLLEVEL", 1 ) )) 2260 { 2261 TRACE("Evaluating feature conditions\n"); 2262 2263 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Condition`", &view ); 2264 if (rc == ERROR_SUCCESS) 2265 { 2266 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package ); 2267 msiobj_release( &view->hdr ); 2268 if (rc != ERROR_SUCCESS) 2269 return rc; 2270 } 2271 } 2272 2273 TRACE("Calculating file cost\n"); 2274 calculate_file_cost( package ); 2275 2276 msi_set_property( package->db, L"CostingComplete", L"1", -1 ); 2277 /* set default run level if not set */ 2278 level = msi_dup_property( package->db, L"INSTALLLEVEL" ); 2279 if (!level) msi_set_property( package->db, L"INSTALLLEVEL", L"1", -1 ); 2280 free(level); 2281 2282 if ((rc = MSI_SetFeatureStates( package ))) return rc; 2283 2284 if ((primary_key = msi_dup_property( package->db, L"PRIMARYFOLDER" ))) 2285 { 2286 if ((primary_folder = msi_dup_property( package->db, primary_key ))) 2287 { 2288 if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') || 2289 (primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':') 2290 { 2291 ULARGE_INTEGER free; 2292 ULONGLONG required; 2293 WCHAR buf[21]; 2294 2295 primary_folder[2] = 0; 2296 if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL )) 2297 { 2298 #ifdef __REACTOS__ 2299 swprintf(buf, ARRAY_SIZE(buf), L"%I64u", free.QuadPart / 512); 2300 #else 2301 swprintf( buf, ARRAY_SIZE(buf), L"%lu", free.QuadPart / 512 ); 2302 #endif 2303 msi_set_property( package->db, L"PrimaryVolumeSpaceAvailable", buf, -1 ); 2304 } 2305 required = get_volume_space_required( package ); 2306 #ifdef __REACTOS__ 2307 swprintf( buf, ARRAY_SIZE(buf), L"%I64u", required ); 2308 #else 2309 swprintf( buf, ARRAY_SIZE(buf), L"%lu", required ); 2310 #endif 2311 msi_set_property( package->db, L"PrimaryVolumeSpaceRequired", buf, -1 ); 2312 2313 #ifdef __REACTOS__ 2314 swprintf( buf, ARRAY_SIZE(buf), L"%I64u", (free.QuadPart / 512) - required ); 2315 #else 2316 swprintf( buf, ARRAY_SIZE(buf), L"%lu", (free.QuadPart / 512) - required ); 2317 #endif 2318 msi_set_property( package->db, L"PrimaryVolumeSpaceRemaining", buf, -1 ); 2319 msi_set_property( package->db, L"PrimaryVolumePath", primary_folder, 2 ); 2320 } 2321 free( primary_folder ); 2322 } 2323 free( primary_key ); 2324 } 2325 2326 /* FIXME: check volume disk space */ 2327 msi_set_property( package->db, L"OutOfDiskSpace", L"0", -1 ); 2328 msi_set_property( package->db, L"OutOfNoRbDiskSpace", L"0", -1 ); 2329 2330 return ERROR_SUCCESS; 2331 } 2332 2333 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size ) 2334 { 2335 BYTE *data; 2336 2337 if (!value) 2338 { 2339 *size = sizeof(WCHAR); 2340 *type = REG_SZ; 2341 if ((data = malloc( *size ))) *(WCHAR *)data = 0; 2342 return data; 2343 } 2344 if (value[0]=='#' && value[1]!='#' && value[1]!='%') 2345 { 2346 if (value[1]=='x') 2347 { 2348 LPWSTR ptr; 2349 CHAR byte[5]; 2350 LPWSTR deformated = NULL; 2351 int count; 2352 2353 deformat_string(package, &value[2], &deformated); 2354 2355 /* binary value type */ 2356 ptr = deformated; 2357 *type = REG_BINARY; 2358 if (lstrlenW(ptr)%2) 2359 *size = (lstrlenW(ptr)/2)+1; 2360 else 2361 *size = lstrlenW(ptr)/2; 2362 2363 data = malloc(*size); 2364 2365 byte[0] = '0'; 2366 byte[1] = 'x'; 2367 byte[4] = 0; 2368 count = 0; 2369 /* if uneven pad with a zero in front */ 2370 if (lstrlenW(ptr)%2) 2371 { 2372 byte[2]= '0'; 2373 byte[3]= *ptr; 2374 ptr++; 2375 data[count] = (BYTE)strtol(byte,NULL,0); 2376 count ++; 2377 TRACE("Uneven byte count\n"); 2378 } 2379 while (*ptr) 2380 { 2381 byte[2]= *ptr; 2382 ptr++; 2383 byte[3]= *ptr; 2384 ptr++; 2385 data[count] = (BYTE)strtol(byte,NULL,0); 2386 count ++; 2387 } 2388 free(deformated); 2389 2390 TRACE( "data %lu bytes(%u)\n", *size, count ); 2391 } 2392 else 2393 { 2394 LPWSTR deformated; 2395 LPWSTR p; 2396 DWORD d = 0; 2397 deformat_string(package, &value[1], &deformated); 2398 2399 *type=REG_DWORD; 2400 *size = sizeof(DWORD); 2401 data = malloc(*size); 2402 p = deformated; 2403 if (*p == '-') 2404 p++; 2405 while (*p) 2406 { 2407 if ( (*p < '0') || (*p > '9') ) 2408 break; 2409 d *= 10; 2410 d += (*p - '0'); 2411 p++; 2412 } 2413 if (deformated[0] == '-') 2414 d = -d; 2415 *(DWORD *)data = d; 2416 TRACE( "DWORD %lu\n", *(DWORD *)data); 2417 2418 free(deformated); 2419 } 2420 } 2421 else 2422 { 2423 const WCHAR *ptr = value; 2424 2425 *type = REG_SZ; 2426 if (value[0] == '#') 2427 { 2428 ptr++; len--; 2429 if (value[1] == '%') 2430 { 2431 ptr++; len--; 2432 *type = REG_EXPAND_SZ; 2433 } 2434 } 2435 data = (BYTE *)msi_strdupW( ptr, len ); 2436 if (len > lstrlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ; 2437 *size = (len + 1) * sizeof(WCHAR); 2438 } 2439 return data; 2440 } 2441 2442 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key ) 2443 { 2444 const WCHAR *ret; 2445 2446 switch (root) 2447 { 2448 case -1: 2449 if (msi_get_property_int( package->db, L"ALLUSERS", 0 )) 2450 { 2451 *root_key = HKEY_LOCAL_MACHINE; 2452 ret = L"HKEY_LOCAL_MACHINE\\"; 2453 } 2454 else 2455 { 2456 *root_key = HKEY_CURRENT_USER; 2457 ret = L"HKEY_CURRENT_USER\\"; 2458 } 2459 break; 2460 case 0: 2461 *root_key = HKEY_CLASSES_ROOT; 2462 ret = L"HKEY_CLASSES_ROOT\\"; 2463 break; 2464 case 1: 2465 *root_key = HKEY_CURRENT_USER; 2466 ret = L"HKEY_CURRENT_USER\\"; 2467 break; 2468 case 2: 2469 *root_key = HKEY_LOCAL_MACHINE; 2470 ret = L"HKEY_LOCAL_MACHINE\\"; 2471 break; 2472 case 3: 2473 *root_key = HKEY_USERS; 2474 ret = L"HKEY_USERS\\"; 2475 break; 2476 default: 2477 ERR("Unknown root %i\n", root); 2478 return NULL; 2479 } 2480 2481 return ret; 2482 } 2483 2484 static inline REGSAM get_registry_view( const MSICOMPONENT *comp ) 2485 { 2486 REGSAM view = 0; 2487 if (is_wow64 || is_64bit) 2488 view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY; 2489 return view; 2490 } 2491 2492 static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create, REGSAM access ) 2493 { 2494 WCHAR *subkey, *p, *q; 2495 HKEY hkey, ret = NULL; 2496 LONG res; 2497 2498 access |= get_registry_view( comp ); 2499 2500 if (!(subkey = wcsdup( path ))) return NULL; 2501 p = subkey; 2502 if ((q = wcschr( p, '\\' ))) *q = 0; 2503 if (create) 2504 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL ); 2505 else 2506 res = RegOpenKeyExW( root, subkey, 0, access, &hkey ); 2507 if (res) 2508 { 2509 TRACE( "failed to open key %s (%ld)\n", debugstr_w(subkey), res ); 2510 free( subkey ); 2511 return NULL; 2512 } 2513 if (q && q[1]) 2514 { 2515 ret = open_key( comp, hkey, q + 1, create, access ); 2516 RegCloseKey( hkey ); 2517 } 2518 else ret = hkey; 2519 free( subkey ); 2520 return ret; 2521 } 2522 2523 static BOOL is_special_entry( const WCHAR *name ) 2524 { 2525 return (name && (name[0] == '*' || name[0] == '+') && !name[1]); 2526 } 2527 2528 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count ) 2529 { 2530 const WCHAR *p = str; 2531 WCHAR **ret; 2532 int i = 0; 2533 2534 *count = 0; 2535 if (!str) return NULL; 2536 while ((p - str) < len) 2537 { 2538 p += lstrlenW( p ) + 1; 2539 (*count)++; 2540 } 2541 if (!(ret = malloc( *count * sizeof(WCHAR *) ))) return NULL; 2542 p = str; 2543 while ((p - str) < len) 2544 { 2545 if (!(ret[i] = wcsdup( p ))) 2546 { 2547 for (; i >= 0; i--) free( ret[i] ); 2548 free( ret ); 2549 return NULL; 2550 } 2551 p += lstrlenW( p ) + 1; 2552 i++; 2553 } 2554 return ret; 2555 } 2556 2557 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count, 2558 WCHAR **right, DWORD right_count, DWORD *size ) 2559 { 2560 WCHAR *ret, *p; 2561 unsigned int i; 2562 2563 *size = sizeof(WCHAR); 2564 for (i = 0; i < left_count; i++) *size += (lstrlenW( left[i] ) + 1) * sizeof(WCHAR); 2565 for (i = 0; i < right_count; i++) *size += (lstrlenW( right[i] ) + 1) * sizeof(WCHAR); 2566 2567 if (!(ret = p = malloc( *size ))) return NULL; 2568 2569 for (i = 0; i < left_count; i++) 2570 { 2571 lstrcpyW( p, left[i] ); 2572 p += lstrlenW( p ) + 1; 2573 } 2574 for (i = 0; i < right_count; i++) 2575 { 2576 lstrcpyW( p, right[i] ); 2577 p += lstrlenW( p ) + 1; 2578 } 2579 *p = 0; 2580 return ret; 2581 } 2582 2583 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count, 2584 WCHAR **new, DWORD new_count ) 2585 { 2586 DWORD ret = old_count; 2587 unsigned int i, j, k; 2588 2589 for (i = 0; i < new_count; i++) 2590 { 2591 for (j = 0; j < old_count; j++) 2592 { 2593 if (old[j] && !wcscmp( new[i], old[j] )) 2594 { 2595 free( old[j] ); 2596 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; } 2597 old[k] = NULL; 2598 ret--; 2599 } 2600 } 2601 } 2602 return ret; 2603 } 2604 2605 enum join_op 2606 { 2607 JOIN_OP_APPEND, 2608 JOIN_OP_PREPEND, 2609 JOIN_OP_REPLACE 2610 }; 2611 2612 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count, 2613 WCHAR **new, DWORD new_count, DWORD *size ) 2614 { 2615 switch (op) 2616 { 2617 case JOIN_OP_APPEND: 2618 old_count = remove_duplicate_values( old, old_count, new, new_count ); 2619 return flatten_multi_string_values( old, old_count, new, new_count, size ); 2620 2621 case JOIN_OP_PREPEND: 2622 old_count = remove_duplicate_values( old, old_count, new, new_count ); 2623 return flatten_multi_string_values( new, new_count, old, old_count, size ); 2624 2625 case JOIN_OP_REPLACE: 2626 return flatten_multi_string_values( new, new_count, NULL, 0, size ); 2627 2628 default: 2629 ERR("unhandled join op %u\n", op); 2630 return NULL; 2631 } 2632 } 2633 2634 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size, 2635 BYTE *new_value, DWORD new_size, DWORD *size ) 2636 { 2637 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0; 2638 const WCHAR *new_ptr = NULL, *old_ptr = NULL; 2639 enum join_op op = JOIN_OP_REPLACE; 2640 WCHAR **old = NULL, **new = NULL; 2641 BYTE *ret; 2642 2643 if (new_size / sizeof(WCHAR) - 1 > 1) 2644 { 2645 new_ptr = (const WCHAR *)new_value; 2646 new_len = new_size / sizeof(WCHAR) - 1; 2647 2648 if (!new_ptr[0] && new_ptr[new_len - 1]) 2649 { 2650 op = JOIN_OP_APPEND; 2651 new_len--; 2652 new_ptr++; 2653 } 2654 else if (new_ptr[0] && !new_ptr[new_len - 1]) 2655 { 2656 op = JOIN_OP_PREPEND; 2657 new_len--; 2658 } 2659 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1]) 2660 { 2661 op = JOIN_OP_REPLACE; 2662 new_len -= 2; 2663 new_ptr++; 2664 } 2665 new = split_multi_string_values( new_ptr, new_len, &new_count ); 2666 } 2667 if (old_size / sizeof(WCHAR) - 1 > 1) 2668 { 2669 old_ptr = (const WCHAR *)old_value; 2670 old_len = old_size / sizeof(WCHAR) - 1; 2671 old = split_multi_string_values( old_ptr, old_len, &old_count ); 2672 } 2673 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size ); 2674 for (i = 0; i < old_count; i++) free( old[i] ); 2675 for (i = 0; i < new_count; i++) free( new[i] ); 2676 free( old ); 2677 free( new ); 2678 return ret; 2679 } 2680 2681 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size ) 2682 { 2683 BYTE *ret; 2684 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL; 2685 if (!(ret = malloc( *size ))) return NULL; 2686 RegQueryValueExW( hkey, name, NULL, type, ret, size ); 2687 return ret; 2688 } 2689 2690 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) 2691 { 2692 MSIPACKAGE *package = param; 2693 BYTE *new_value, *old_value = NULL; 2694 HKEY root_key, hkey; 2695 DWORD type, old_type, new_size, old_size = 0; 2696 LPWSTR deformated, uikey; 2697 const WCHAR *szRoot, *component, *name, *key, *str; 2698 MSICOMPONENT *comp; 2699 MSIRECORD * uirow; 2700 INT root; 2701 BOOL check_first = FALSE; 2702 int len; 2703 2704 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 ); 2705 2706 component = MSI_RecordGetString(row, 6); 2707 comp = msi_get_loaded_component(package,component); 2708 if (!comp) 2709 return ERROR_SUCCESS; 2710 2711 comp->Action = msi_get_component_action( package, comp ); 2712 if (comp->Action != INSTALLSTATE_LOCAL && comp->Action != INSTALLSTATE_SOURCE) 2713 { 2714 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 2715 return ERROR_SUCCESS; 2716 } 2717 2718 name = MSI_RecordGetString(row, 4); 2719 if( MSI_RecordIsNull(row,5) && name ) 2720 { 2721 /* null values can have special meanings */ 2722 if (name[0]=='-' && name[1] == 0) 2723 return ERROR_SUCCESS; 2724 if ((name[0] == '+' || name[0] == '*') && !name[1]) 2725 check_first = TRUE; 2726 } 2727 2728 root = MSI_RecordGetInteger(row,2); 2729 key = MSI_RecordGetString(row, 3); 2730 2731 szRoot = get_root_key( package, root, &root_key ); 2732 if (!szRoot) 2733 return ERROR_SUCCESS; 2734 2735 deformat_string(package, key , &deformated); 2736 uikey = malloc( (wcslen(deformated) + wcslen(szRoot) + 1) * sizeof(WCHAR) ); 2737 lstrcpyW(uikey,szRoot); 2738 lstrcatW(uikey,deformated); 2739 2740 if (!(hkey = open_key( comp, root_key, deformated, TRUE, KEY_QUERY_VALUE | KEY_SET_VALUE ))) 2741 { 2742 ERR("Could not create key %s\n", debugstr_w(deformated)); 2743 free(uikey); 2744 free(deformated); 2745 return ERROR_FUNCTION_FAILED; 2746 } 2747 free( deformated ); 2748 str = msi_record_get_string( row, 5, NULL ); 2749 len = deformat_string( package, str, &deformated ); 2750 new_value = parse_value( package, deformated, len, &type, &new_size ); 2751 2752 free( deformated ); 2753 deformat_string(package, name, &deformated); 2754 2755 if (!is_special_entry( name )) 2756 { 2757 old_value = reg_get_value( hkey, deformated, &old_type, &old_size ); 2758 if (type == REG_MULTI_SZ) 2759 { 2760 BYTE *new; 2761 if (old_value && old_type != REG_MULTI_SZ) 2762 { 2763 free( old_value ); 2764 old_value = NULL; 2765 old_size = 0; 2766 } 2767 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size ); 2768 free( new_value ); 2769 new_value = new; 2770 } 2771 if (!check_first) 2772 { 2773 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type ); 2774 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size ); 2775 } 2776 else if (!old_value) 2777 { 2778 if (deformated || new_size) 2779 { 2780 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type ); 2781 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size ); 2782 } 2783 } 2784 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey)); 2785 } 2786 RegCloseKey(hkey); 2787 2788 uirow = MSI_CreateRecord(3); 2789 MSI_RecordSetStringW(uirow,2,deformated); 2790 MSI_RecordSetStringW(uirow,1,uikey); 2791 if (type == REG_SZ || type == REG_EXPAND_SZ) 2792 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value); 2793 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 2794 msiobj_release( &uirow->hdr ); 2795 2796 free(new_value); 2797 free(old_value); 2798 free(deformated); 2799 free(uikey); 2800 2801 return ERROR_SUCCESS; 2802 } 2803 2804 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) 2805 { 2806 MSIQUERY *view; 2807 UINT rc; 2808 2809 if (package->script == SCRIPT_NONE) 2810 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteRegistryValues"); 2811 2812 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Registry`", &view); 2813 if (rc != ERROR_SUCCESS) 2814 return ERROR_SUCCESS; 2815 2816 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package); 2817 msiobj_release(&view->hdr); 2818 return rc; 2819 } 2820 2821 static int is_key_empty(const MSICOMPONENT *comp, HKEY root, const WCHAR *path) 2822 { 2823 DWORD subkeys, values; 2824 HKEY key; 2825 LONG res; 2826 2827 key = open_key(comp, root, path, FALSE, KEY_READ); 2828 if (!key) return 0; 2829 2830 res = RegQueryInfoKeyW(key, 0, 0, 0, &subkeys, 0, 0, &values, 0, 0, 0, 0); 2831 RegCloseKey(key); 2832 2833 return !res && !subkeys && !values; 2834 } 2835 2836 static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path ) 2837 { 2838 LONG res = ERROR_SUCCESS; 2839 REGSAM access = get_registry_view( comp ); 2840 WCHAR *subkey, *p; 2841 HKEY hkey; 2842 2843 if (!(subkey = wcsdup( path ))) return; 2844 do 2845 { 2846 if ((p = wcsrchr( subkey, '\\' ))) 2847 { 2848 *p = 0; 2849 if (!p[1]) continue; /* trailing backslash */ 2850 hkey = open_key( comp, root, subkey, FALSE, READ_CONTROL ); 2851 if (!hkey) break; 2852 if (!is_key_empty(comp, hkey, p + 1)) 2853 { 2854 RegCloseKey(hkey); 2855 break; 2856 } 2857 res = RegDeleteKeyExW( hkey, p + 1, access, 0 ); 2858 RegCloseKey( hkey ); 2859 } 2860 else if (is_key_empty(comp, root, subkey)) 2861 res = RegDeleteKeyExW( root, subkey, access, 0 ); 2862 if (res) 2863 { 2864 TRACE( "failed to delete key %s (%ld)\n", debugstr_w(subkey), res ); 2865 break; 2866 } 2867 } while (p); 2868 free( subkey ); 2869 } 2870 2871 static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value ) 2872 { 2873 LONG res; 2874 HKEY hkey; 2875 2876 if ((hkey = open_key( comp, root, path, FALSE, KEY_SET_VALUE | KEY_QUERY_VALUE ))) 2877 { 2878 if ((res = RegDeleteValueW( hkey, value ))) 2879 TRACE( "failed to delete value %s (%ld)\n", debugstr_w(value), res ); 2880 2881 RegCloseKey( hkey ); 2882 if (is_key_empty(comp, root, path)) 2883 { 2884 TRACE("removing empty key %s\n", debugstr_w(path)); 2885 delete_key( comp, root, path ); 2886 } 2887 } 2888 } 2889 2890 static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path ) 2891 { 2892 LONG res; 2893 HKEY hkey; 2894 2895 if (!(hkey = open_key( comp, root, path, FALSE, KEY_ALL_ACCESS ))) return; 2896 res = RegDeleteTreeW( hkey, NULL ); 2897 if (res) TRACE( "failed to delete subtree of %s (%ld)\n", debugstr_w(path), res ); 2898 delete_key( comp, root, path ); 2899 RegCloseKey( hkey ); 2900 } 2901 2902 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param ) 2903 { 2904 MSIPACKAGE *package = param; 2905 LPCWSTR component, name, key_str, root_key_str; 2906 LPWSTR deformated_key, deformated_name, ui_key_str; 2907 MSICOMPONENT *comp; 2908 MSIRECORD *uirow; 2909 BOOL delete_key = FALSE; 2910 HKEY hkey_root; 2911 UINT size; 2912 INT root; 2913 2914 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 ); 2915 2916 component = MSI_RecordGetString( row, 6 ); 2917 comp = msi_get_loaded_component( package, component ); 2918 if (!comp) 2919 return ERROR_SUCCESS; 2920 2921 comp->Action = msi_get_component_action( package, comp ); 2922 if (comp->Action != INSTALLSTATE_ABSENT) 2923 { 2924 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 2925 return ERROR_SUCCESS; 2926 } 2927 2928 name = MSI_RecordGetString( row, 4 ); 2929 if (MSI_RecordIsNull( row, 5 ) && name ) 2930 { 2931 if (name[0] == '+' && !name[1]) 2932 return ERROR_SUCCESS; 2933 if ((name[0] == '-' || name[0] == '*') && !name[1]) 2934 { 2935 delete_key = TRUE; 2936 name = NULL; 2937 } 2938 } 2939 2940 root = MSI_RecordGetInteger( row, 2 ); 2941 key_str = MSI_RecordGetString( row, 3 ); 2942 2943 root_key_str = get_root_key( package, root, &hkey_root ); 2944 if (!root_key_str) 2945 return ERROR_SUCCESS; 2946 2947 deformat_string( package, key_str, &deformated_key ); 2948 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1; 2949 ui_key_str = malloc( size * sizeof(WCHAR) ); 2950 lstrcpyW( ui_key_str, root_key_str ); 2951 lstrcatW( ui_key_str, deformated_key ); 2952 2953 deformat_string( package, name, &deformated_name ); 2954 2955 if (delete_key) delete_tree( comp, hkey_root, deformated_key ); 2956 else delete_value( comp, hkey_root, deformated_key, deformated_name ); 2957 free( deformated_key ); 2958 2959 uirow = MSI_CreateRecord( 2 ); 2960 MSI_RecordSetStringW( uirow, 1, ui_key_str ); 2961 MSI_RecordSetStringW( uirow, 2, deformated_name ); 2962 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 2963 msiobj_release( &uirow->hdr ); 2964 2965 free( ui_key_str ); 2966 free( deformated_name ); 2967 return ERROR_SUCCESS; 2968 } 2969 2970 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param ) 2971 { 2972 MSIPACKAGE *package = param; 2973 LPCWSTR component, name, key_str, root_key_str; 2974 LPWSTR deformated_key, deformated_name, ui_key_str; 2975 MSICOMPONENT *comp; 2976 MSIRECORD *uirow; 2977 BOOL delete_key = FALSE; 2978 HKEY hkey_root; 2979 UINT size; 2980 INT root; 2981 2982 component = MSI_RecordGetString( row, 5 ); 2983 comp = msi_get_loaded_component( package, component ); 2984 if (!comp) 2985 return ERROR_SUCCESS; 2986 2987 comp->Action = msi_get_component_action( package, comp ); 2988 if (comp->Action != INSTALLSTATE_LOCAL) 2989 { 2990 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 2991 return ERROR_SUCCESS; 2992 } 2993 2994 if ((name = MSI_RecordGetString( row, 4 ))) 2995 { 2996 if (name[0] == '-' && !name[1]) 2997 { 2998 delete_key = TRUE; 2999 name = NULL; 3000 } 3001 } 3002 3003 root = MSI_RecordGetInteger( row, 2 ); 3004 key_str = MSI_RecordGetString( row, 3 ); 3005 3006 root_key_str = get_root_key( package, root, &hkey_root ); 3007 if (!root_key_str) 3008 return ERROR_SUCCESS; 3009 3010 deformat_string( package, key_str, &deformated_key ); 3011 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1; 3012 ui_key_str = malloc( size * sizeof(WCHAR) ); 3013 lstrcpyW( ui_key_str, root_key_str ); 3014 lstrcatW( ui_key_str, deformated_key ); 3015 3016 deformat_string( package, name, &deformated_name ); 3017 3018 if (delete_key) delete_tree( comp, hkey_root, deformated_key ); 3019 else delete_value( comp, hkey_root, deformated_key, deformated_name ); 3020 free( deformated_key ); 3021 3022 uirow = MSI_CreateRecord( 2 ); 3023 MSI_RecordSetStringW( uirow, 1, ui_key_str ); 3024 MSI_RecordSetStringW( uirow, 2, deformated_name ); 3025 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 3026 msiobj_release( &uirow->hdr ); 3027 3028 free( ui_key_str ); 3029 free( deformated_name ); 3030 return ERROR_SUCCESS; 3031 } 3032 3033 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package ) 3034 { 3035 MSIQUERY *view; 3036 UINT rc; 3037 3038 if (package->script == SCRIPT_NONE) 3039 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveRegistryValues"); 3040 3041 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view ); 3042 if (rc == ERROR_SUCCESS) 3043 { 3044 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package ); 3045 msiobj_release( &view->hdr ); 3046 if (rc != ERROR_SUCCESS) 3047 return rc; 3048 } 3049 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveRegistry`", &view ); 3050 if (rc == ERROR_SUCCESS) 3051 { 3052 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package ); 3053 msiobj_release( &view->hdr ); 3054 if (rc != ERROR_SUCCESS) 3055 return rc; 3056 } 3057 return ERROR_SUCCESS; 3058 } 3059 3060 static UINT ACTION_InstallInitialize(MSIPACKAGE *package) 3061 { 3062 return ERROR_SUCCESS; 3063 } 3064 3065 3066 static UINT ACTION_InstallValidate(MSIPACKAGE *package) 3067 { 3068 MSICOMPONENT *comp; 3069 DWORD total = 0, count = 0; 3070 MSIQUERY *view; 3071 MSIFEATURE *feature; 3072 MSIFILE *file; 3073 UINT rc; 3074 3075 TRACE("InstallValidate\n"); 3076 3077 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view ); 3078 if (rc == ERROR_SUCCESS) 3079 { 3080 rc = MSI_IterateRecords( view, &count, NULL, package ); 3081 msiobj_release( &view->hdr ); 3082 if (rc != ERROR_SUCCESS) 3083 return rc; 3084 total += count * REG_PROGRESS_VALUE; 3085 } 3086 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 3087 total += COMPONENT_PROGRESS_VALUE; 3088 3089 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 3090 total += file->FileSize; 3091 3092 msi_ui_progress( package, 0, total, 0, 0 ); 3093 3094 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 3095 { 3096 TRACE("Feature: %s Installed %d Request %d Action %d\n", 3097 debugstr_w(feature->Feature), feature->Installed, 3098 feature->ActionRequest, feature->Action); 3099 } 3100 return ERROR_SUCCESS; 3101 } 3102 3103 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param) 3104 { 3105 MSIPACKAGE* package = param; 3106 const WCHAR *cond, *message; 3107 UINT r; 3108 3109 cond = MSI_RecordGetString(row, 1); 3110 r = MSI_EvaluateConditionW(package, cond); 3111 if (r == MSICONDITION_FALSE) 3112 { 3113 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) 3114 { 3115 WCHAR *deformated; 3116 message = MSI_RecordGetString(row, 2); 3117 deformat_string(package, message, &deformated); 3118 MessageBoxW(NULL, deformated, L"Install Failed", MB_OK); 3119 free(deformated); 3120 } 3121 3122 return ERROR_INSTALL_FAILURE; 3123 } 3124 3125 return ERROR_SUCCESS; 3126 } 3127 3128 static UINT ACTION_LaunchConditions(MSIPACKAGE *package) 3129 { 3130 MSIQUERY *view; 3131 UINT rc; 3132 3133 TRACE("Checking launch conditions\n"); 3134 3135 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `LaunchCondition`", &view); 3136 if (rc != ERROR_SUCCESS) 3137 return ERROR_SUCCESS; 3138 3139 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package); 3140 msiobj_release(&view->hdr); 3141 return rc; 3142 } 3143 3144 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp ) 3145 { 3146 3147 if (!cmp->KeyPath) 3148 return wcsdup( msi_get_target_folder( package, cmp->Directory ) ); 3149 3150 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) 3151 { 3152 MSIRECORD *row; 3153 UINT root, len; 3154 LPWSTR deformated, buffer, deformated_name; 3155 LPCWSTR key, name; 3156 3157 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Registry` WHERE `Registry` = '%s'", cmp->KeyPath); 3158 if (!row) 3159 return NULL; 3160 3161 root = MSI_RecordGetInteger(row,2); 3162 key = MSI_RecordGetString(row, 3); 3163 name = MSI_RecordGetString(row, 4); 3164 deformat_string(package, key , &deformated); 3165 deformat_string(package, name, &deformated_name); 3166 3167 len = lstrlenW(deformated) + 6; 3168 if (deformated_name) 3169 len+=lstrlenW(deformated_name); 3170 3171 buffer = malloc(len * sizeof(WCHAR)); 3172 3173 if (deformated_name) 3174 swprintf(buffer, len, L"%02d:\\%s\\%s", root, deformated, deformated_name); 3175 else 3176 swprintf(buffer, len, L"%02d:\\%s\\", root, deformated); 3177 3178 free(deformated); 3179 free(deformated_name); 3180 msiobj_release(&row->hdr); 3181 3182 return buffer; 3183 } 3184 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource) 3185 { 3186 FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); 3187 return NULL; 3188 } 3189 else 3190 { 3191 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath ); 3192 3193 if (file) 3194 return wcsdup( file->TargetPath ); 3195 } 3196 return NULL; 3197 } 3198 3199 static HKEY open_shared_dlls_key( MSICOMPONENT *comp, BOOL create, REGSAM access ) 3200 { 3201 return open_key( comp, HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs", 3202 create, access ); 3203 } 3204 3205 static UINT get_shared_dlls_count( MSICOMPONENT *comp ) 3206 { 3207 DWORD count, type, sz = sizeof(count); 3208 HKEY hkey = open_shared_dlls_key( comp, FALSE, KEY_READ ); 3209 if (RegQueryValueExW( hkey, comp->FullKeypath, NULL, &type, (BYTE *)&count, &sz )) count = 0; 3210 RegCloseKey( hkey ); 3211 return count; 3212 } 3213 3214 static void write_shared_dlls_count( MSICOMPONENT *comp, const WCHAR *path, INT count ) 3215 { 3216 HKEY hkey = open_shared_dlls_key( comp, TRUE, KEY_SET_VALUE ); 3217 if (count > 0) 3218 msi_reg_set_val_dword( hkey, path, count ); 3219 else 3220 RegDeleteValueW( hkey, path ); 3221 RegCloseKey(hkey); 3222 } 3223 3224 static void refcount_component( MSIPACKAGE *package, MSICOMPONENT *comp ) 3225 { 3226 MSIFEATURE *feature; 3227 INT count = 0; 3228 BOOL write = FALSE; 3229 3230 /* only refcount DLLs */ 3231 if (!comp->KeyPath || comp->assembly || comp->Attributes & msidbComponentAttributesRegistryKeyPath || 3232 comp->Attributes & msidbComponentAttributesODBCDataSource) 3233 write = FALSE; 3234 else 3235 { 3236 count = get_shared_dlls_count( comp ); 3237 write = (count > 0); 3238 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount) 3239 write = TRUE; 3240 } 3241 3242 /* increment counts */ 3243 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 3244 { 3245 ComponentList *cl; 3246 3247 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL) 3248 continue; 3249 3250 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 3251 { 3252 if ( cl->component == comp ) 3253 count++; 3254 } 3255 } 3256 3257 /* decrement counts */ 3258 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 3259 { 3260 ComponentList *cl; 3261 3262 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT) 3263 continue; 3264 3265 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 3266 { 3267 if ( cl->component == comp ) 3268 count--; 3269 } 3270 } 3271 3272 /* ref count all the files in the component */ 3273 if (write) 3274 { 3275 MSIFILE *file; 3276 3277 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 3278 { 3279 if (file->Component == comp) 3280 write_shared_dlls_count( comp, file->TargetPath, count ); 3281 } 3282 } 3283 3284 /* add a count for permanent */ 3285 if (comp->Attributes & msidbComponentAttributesPermanent) 3286 count ++; 3287 3288 comp->RefCount = count; 3289 3290 if (write) 3291 write_shared_dlls_count( comp, comp->FullKeypath, comp->RefCount ); 3292 } 3293 3294 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp ) 3295 { 3296 if (comp->assembly) 3297 { 3298 DWORD len = lstrlenW( L"<\\" ) + lstrlenW( comp->assembly->display_name ); 3299 WCHAR *keypath = malloc( (len + 1) * sizeof(WCHAR) ); 3300 3301 if (keypath) 3302 { 3303 lstrcpyW( keypath, L"<\\" ); 3304 lstrcatW( keypath, comp->assembly->display_name ); 3305 } 3306 return keypath; 3307 } 3308 return resolve_keypath( package, comp ); 3309 } 3310 3311 static UINT ACTION_ProcessComponents(MSIPACKAGE *package) 3312 { 3313 WCHAR squashed_pc[SQUASHED_GUID_SIZE], squashed_cc[SQUASHED_GUID_SIZE]; 3314 UINT rc; 3315 MSICOMPONENT *comp; 3316 HKEY hkey; 3317 3318 TRACE("\n"); 3319 3320 msi_set_sourcedir_props(package, FALSE); 3321 3322 if (package->script == SCRIPT_NONE) 3323 return msi_schedule_action(package, SCRIPT_INSTALL, L"ProcessComponents"); 3324 3325 squash_guid( package->ProductCode, squashed_pc ); 3326 3327 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 3328 { 3329 MSIRECORD *uirow; 3330 INSTALLSTATE action; 3331 3332 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 ); 3333 if (!comp->ComponentId) 3334 continue; 3335 3336 squash_guid( comp->ComponentId, squashed_cc ); 3337 free( comp->FullKeypath ); 3338 comp->FullKeypath = build_full_keypath( package, comp ); 3339 3340 refcount_component( package, comp ); 3341 3342 if (package->need_rollback) action = comp->Installed; 3343 else action = comp->ActionRequest; 3344 3345 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n", 3346 debugstr_w(comp->Component), debugstr_w(squashed_cc), 3347 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action); 3348 3349 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE) 3350 { 3351 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 3352 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, L"S-1-5-18", &hkey, TRUE); 3353 else 3354 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE); 3355 3356 if (rc != ERROR_SUCCESS) 3357 continue; 3358 3359 if (comp->Attributes & msidbComponentAttributesPermanent) 3360 { 3361 msi_reg_set_val_str(hkey, L"00000000000000000000000000000000", comp->FullKeypath); 3362 } 3363 if (action == INSTALLSTATE_LOCAL) 3364 msi_reg_set_val_str( hkey, squashed_pc, comp->FullKeypath ); 3365 else 3366 { 3367 MSIFILE *file; 3368 MSIRECORD *row; 3369 LPWSTR ptr, ptr2; 3370 WCHAR source[MAX_PATH]; 3371 WCHAR base[MAX_PATH]; 3372 LPWSTR sourcepath; 3373 3374 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath))) 3375 continue; 3376 3377 if (!(row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Media` WHERE `LastSequence` >= %d " 3378 L"ORDER BY `DiskId`", file->Sequence))) 3379 return ERROR_FUNCTION_FAILED; 3380 3381 swprintf(source, ARRAY_SIZE(source), L"%02d\\", MSI_RecordGetInteger(row, 1)); 3382 ptr2 = wcsrchr(source, '\\') + 1; 3383 msiobj_release(&row->hdr); 3384 3385 lstrcpyW(base, package->PackagePath); 3386 ptr = wcsrchr(base, '\\'); 3387 *(ptr + 1) = '\0'; 3388 3389 sourcepath = msi_resolve_file_source(package, file); 3390 ptr = sourcepath + lstrlenW(base); 3391 lstrcpyW(ptr2, ptr); 3392 free(sourcepath); 3393 3394 msi_reg_set_val_str( hkey, squashed_pc, source ); 3395 } 3396 RegCloseKey(hkey); 3397 } 3398 else if (action == INSTALLSTATE_ABSENT) 3399 { 3400 if (comp->num_clients <= 0) 3401 { 3402 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 3403 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, L"S-1-5-18" ); 3404 else 3405 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL ); 3406 3407 if (rc != ERROR_SUCCESS) WARN( "failed to delete component key %u\n", rc ); 3408 } 3409 else 3410 { 3411 LONG res; 3412 3413 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 3414 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE ); 3415 else 3416 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ); 3417 3418 if (rc != ERROR_SUCCESS) 3419 { 3420 WARN( "failed to open component key %u\n", rc ); 3421 continue; 3422 } 3423 res = RegDeleteValueW( hkey, squashed_pc ); 3424 RegCloseKey(hkey); 3425 if (res) WARN( "failed to delete component value %ld\n", res ); 3426 } 3427 } 3428 3429 /* UI stuff */ 3430 uirow = MSI_CreateRecord(3); 3431 MSI_RecordSetStringW(uirow,1,package->ProductCode); 3432 MSI_RecordSetStringW(uirow,2,comp->ComponentId); 3433 MSI_RecordSetStringW(uirow,3,comp->FullKeypath); 3434 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 3435 msiobj_release( &uirow->hdr ); 3436 } 3437 return ERROR_SUCCESS; 3438 } 3439 3440 struct typelib 3441 { 3442 CLSID clsid; 3443 LPWSTR source; 3444 LPWSTR path; 3445 ITypeLib *ptLib; 3446 }; 3447 3448 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 3449 LPWSTR lpszName, LONG_PTR lParam) 3450 { 3451 TLIBATTR *attr; 3452 struct typelib *tl_struct = (struct typelib *)lParam; 3453 int sz; 3454 HRESULT res; 3455 3456 if (!IS_INTRESOURCE(lpszName)) 3457 { 3458 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName)); 3459 return TRUE; 3460 } 3461 3462 sz = lstrlenW(tl_struct->source)+4; 3463 3464 if ((INT_PTR)lpszName == 1) 3465 tl_struct->path = wcsdup(tl_struct->source); 3466 else 3467 { 3468 tl_struct->path = malloc(sz * sizeof(WCHAR)); 3469 #ifdef __REACTOS__ 3470 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, (WORD)(INT_PTR)lpszName); 3471 #else 3472 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, lpszName); 3473 #endif 3474 } 3475 3476 TRACE("trying %s\n", debugstr_w(tl_struct->path)); 3477 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib); 3478 if (FAILED(res)) 3479 { 3480 free(tl_struct->path); 3481 tl_struct->path = NULL; 3482 3483 return TRUE; 3484 } 3485 3486 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr); 3487 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid))) 3488 { 3489 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); 3490 return FALSE; 3491 } 3492 3493 free(tl_struct->path); 3494 tl_struct->path = NULL; 3495 3496 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); 3497 ITypeLib_Release(tl_struct->ptLib); 3498 3499 return TRUE; 3500 } 3501 3502 static HMODULE load_library( MSIPACKAGE *package, const WCHAR *filename, DWORD flags ) 3503 { 3504 HMODULE module; 3505 msi_disable_fs_redirection( package ); 3506 module = LoadLibraryExW( filename, NULL, flags ); 3507 msi_revert_fs_redirection( package ); 3508 return module; 3509 } 3510 3511 static HRESULT load_typelib( MSIPACKAGE *package, const WCHAR *filename, REGKIND kind, ITypeLib **lib ) 3512 { 3513 HRESULT hr; 3514 msi_disable_fs_redirection( package ); 3515 hr = LoadTypeLibEx( filename, kind, lib ); 3516 msi_revert_fs_redirection( package ); 3517 return hr; 3518 } 3519 3520 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) 3521 { 3522 MSIPACKAGE* package = param; 3523 LPCWSTR component; 3524 MSICOMPONENT *comp; 3525 MSIFILE *file; 3526 struct typelib tl_struct; 3527 ITypeLib *tlib; 3528 HMODULE module; 3529 HRESULT hr; 3530 3531 component = MSI_RecordGetString(row,3); 3532 comp = msi_get_loaded_component(package,component); 3533 if (!comp) 3534 return ERROR_SUCCESS; 3535 3536 comp->Action = msi_get_component_action( package, comp ); 3537 if (comp->Action != INSTALLSTATE_LOCAL) 3538 { 3539 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 3540 return ERROR_SUCCESS; 3541 } 3542 3543 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath ))) 3544 { 3545 TRACE("component has no key path\n"); 3546 return ERROR_SUCCESS; 3547 } 3548 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); 3549 3550 module = load_library( package, file->TargetPath, LOAD_LIBRARY_AS_DATAFILE ); 3551 if (module) 3552 { 3553 LPCWSTR guid; 3554 guid = MSI_RecordGetString(row,1); 3555 CLSIDFromString( guid, &tl_struct.clsid); 3556 tl_struct.source = wcsdup( file->TargetPath ); 3557 tl_struct.path = NULL; 3558 3559 EnumResourceNamesW(module, L"TYPELIB", Typelib_EnumResNameProc, 3560 (LONG_PTR)&tl_struct); 3561 3562 if (tl_struct.path) 3563 { 3564 LPCWSTR helpid, help_path = NULL; 3565 HRESULT res; 3566 3567 helpid = MSI_RecordGetString(row,6); 3568 3569 if (helpid) help_path = msi_get_target_folder( package, helpid ); 3570 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path ); 3571 3572 if (FAILED(res)) 3573 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path)); 3574 else 3575 TRACE("Registered %s\n", debugstr_w(tl_struct.path)); 3576 3577 ITypeLib_Release(tl_struct.ptLib); 3578 free(tl_struct.path); 3579 } 3580 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source)); 3581 3582 FreeLibrary(module); 3583 free(tl_struct.source); 3584 } 3585 else 3586 { 3587 hr = load_typelib( package, file->TargetPath, REGKIND_REGISTER, &tlib ); 3588 if (FAILED(hr)) 3589 { 3590 ERR( "failed to load type library: %#lx\n", hr ); 3591 return ERROR_INSTALL_FAILURE; 3592 } 3593 3594 ITypeLib_Release(tlib); 3595 } 3596 3597 return ERROR_SUCCESS; 3598 } 3599 3600 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) 3601 { 3602 MSIQUERY *view; 3603 UINT rc; 3604 3605 if (package->script == SCRIPT_NONE) 3606 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterTypeLibraries"); 3607 3608 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `TypeLib`", &view); 3609 if (rc != ERROR_SUCCESS) 3610 return ERROR_SUCCESS; 3611 3612 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package); 3613 msiobj_release(&view->hdr); 3614 return rc; 3615 } 3616 3617 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param ) 3618 { 3619 MSIPACKAGE *package = param; 3620 LPCWSTR component, guid; 3621 MSICOMPONENT *comp; 3622 GUID libid; 3623 UINT version; 3624 LCID language; 3625 SYSKIND syskind; 3626 HRESULT hr; 3627 3628 component = MSI_RecordGetString( row, 3 ); 3629 comp = msi_get_loaded_component( package, component ); 3630 if (!comp) 3631 return ERROR_SUCCESS; 3632 3633 comp->Action = msi_get_component_action( package, comp ); 3634 if (comp->Action != INSTALLSTATE_ABSENT) 3635 { 3636 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 3637 return ERROR_SUCCESS; 3638 } 3639 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); 3640 3641 guid = MSI_RecordGetString( row, 1 ); 3642 CLSIDFromString( guid, &libid ); 3643 version = MSI_RecordGetInteger( row, 4 ); 3644 language = MSI_RecordGetInteger( row, 2 ); 3645 3646 #ifdef _WIN64 3647 syskind = SYS_WIN64; 3648 #else 3649 syskind = SYS_WIN32; 3650 #endif 3651 3652 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind ); 3653 if (FAILED(hr)) 3654 { 3655 WARN( "failed to unregister typelib: %#lx\n", hr ); 3656 } 3657 3658 return ERROR_SUCCESS; 3659 } 3660 3661 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package ) 3662 { 3663 MSIQUERY *view; 3664 UINT rc; 3665 3666 if (package->script == SCRIPT_NONE) 3667 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterTypeLibraries"); 3668 3669 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `TypeLib`", &view ); 3670 if (rc != ERROR_SUCCESS) 3671 return ERROR_SUCCESS; 3672 3673 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package ); 3674 msiobj_release( &view->hdr ); 3675 return rc; 3676 } 3677 3678 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row ) 3679 { 3680 LPCWSTR directory, extension, link_folder; 3681 WCHAR *link_file = NULL, *filename, *new_filename; 3682 3683 directory = MSI_RecordGetString( row, 2 ); 3684 link_folder = msi_get_target_folder( package, directory ); 3685 if (!link_folder) 3686 { 3687 ERR("unable to resolve folder %s\n", debugstr_w(directory)); 3688 return NULL; 3689 } 3690 /* may be needed because of a bug somewhere else */ 3691 msi_create_full_path( package, link_folder ); 3692 3693 filename = msi_dup_record_field( row, 3 ); 3694 if (!filename) return NULL; 3695 msi_reduce_to_long_filename( filename ); 3696 3697 extension = wcsrchr( filename, '.' ); 3698 if (!extension || wcsicmp( extension, L".lnk" )) 3699 { 3700 int len = lstrlenW( filename ); 3701 new_filename = realloc( filename, len * sizeof(WCHAR) + sizeof(L".lnk") ); 3702 if (!new_filename) goto done; 3703 filename = new_filename; 3704 memcpy( filename + len, L".lnk", sizeof(L".lnk") ); 3705 } 3706 link_file = msi_build_directory_name( 2, link_folder, filename ); 3707 3708 done: 3709 free( filename ); 3710 return link_file; 3711 } 3712 3713 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name ) 3714 { 3715 WCHAR *folder, *dest, *path; 3716 3717 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 3718 folder = msi_dup_property( package->db, L"WindowsFolder" ); 3719 else 3720 { 3721 WCHAR *appdata = msi_dup_property( package->db, L"AppDataFolder" ); 3722 folder = msi_build_directory_name( 2, appdata, L"Microsoft\\" ); 3723 free( appdata ); 3724 } 3725 dest = msi_build_directory_name( 3, folder, L"Installer\\", package->ProductCode ); 3726 msi_create_full_path( package, dest ); 3727 path = msi_build_directory_name( 2, dest, icon_name ); 3728 free( folder ); 3729 free( dest ); 3730 return path; 3731 } 3732 3733 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) 3734 { 3735 MSIPACKAGE *package = param; 3736 LPWSTR link_file, deformated, path; 3737 LPCWSTR component, target; 3738 MSICOMPONENT *comp; 3739 IShellLinkW *sl = NULL; 3740 IPersistFile *pf = NULL; 3741 HRESULT res; 3742 3743 component = MSI_RecordGetString(row, 4); 3744 comp = msi_get_loaded_component(package, component); 3745 if (!comp) 3746 return ERROR_SUCCESS; 3747 3748 comp->Action = msi_get_component_action( package, comp ); 3749 if (comp->Action != INSTALLSTATE_LOCAL) 3750 { 3751 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 3752 return ERROR_SUCCESS; 3753 } 3754 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); 3755 3756 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 3757 &IID_IShellLinkW, (LPVOID *) &sl ); 3758 3759 if (FAILED( res )) 3760 { 3761 ERR("CLSID_ShellLink not available\n"); 3762 goto err; 3763 } 3764 3765 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); 3766 if (FAILED( res )) 3767 { 3768 ERR("QueryInterface(IID_IPersistFile) failed\n"); 3769 goto err; 3770 } 3771 3772 target = MSI_RecordGetString(row, 5); 3773 if (wcschr(target, '[')) 3774 { 3775 deformat_string( package, target, &path ); 3776 TRACE("target path is %s\n", debugstr_w(path)); 3777 IShellLinkW_SetPath( sl, path ); 3778 free( path ); 3779 } 3780 else 3781 { 3782 FIXME("poorly handled shortcut format, advertised shortcut\n"); 3783 path = resolve_keypath( package, comp ); 3784 IShellLinkW_SetPath( sl, path ); 3785 free( path ); 3786 } 3787 3788 if (!MSI_RecordIsNull(row,6)) 3789 { 3790 LPCWSTR arguments = MSI_RecordGetString(row, 6); 3791 deformat_string(package, arguments, &deformated); 3792 IShellLinkW_SetArguments(sl,deformated); 3793 free(deformated); 3794 } 3795 3796 if (!MSI_RecordIsNull(row,7)) 3797 { 3798 LPCWSTR description = MSI_RecordGetString(row, 7); 3799 IShellLinkW_SetDescription(sl, description); 3800 } 3801 3802 if (!MSI_RecordIsNull(row,8)) 3803 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); 3804 3805 if (!MSI_RecordIsNull(row,9)) 3806 { 3807 INT index; 3808 LPCWSTR icon = MSI_RecordGetString(row, 9); 3809 3810 path = msi_build_icon_path(package, icon); 3811 index = MSI_RecordGetInteger(row,10); 3812 3813 /* no value means 0 */ 3814 if (index == MSI_NULL_INTEGER) 3815 index = 0; 3816 3817 IShellLinkW_SetIconLocation(sl, path, index); 3818 free(path); 3819 } 3820 3821 if (!MSI_RecordIsNull(row,11)) 3822 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); 3823 3824 if (!MSI_RecordIsNull(row,12)) 3825 { 3826 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 ); 3827 full_path = msi_get_target_folder( package, wkdir ); 3828 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path ); 3829 } 3830 3831 link_file = get_link_file(package, row); 3832 TRACE("Writing shortcut to %s\n", debugstr_w(link_file)); 3833 3834 msi_disable_fs_redirection( package ); 3835 IPersistFile_Save(pf, link_file, FALSE); 3836 msi_revert_fs_redirection( package ); 3837 3838 free(link_file); 3839 3840 err: 3841 if (pf) 3842 IPersistFile_Release( pf ); 3843 if (sl) 3844 IShellLinkW_Release( sl ); 3845 3846 return ERROR_SUCCESS; 3847 } 3848 3849 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) 3850 { 3851 MSIQUERY *view; 3852 HRESULT res; 3853 UINT rc; 3854 3855 if (package->script == SCRIPT_NONE) 3856 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateShortcuts"); 3857 3858 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Shortcut`", &view); 3859 if (rc != ERROR_SUCCESS) 3860 return ERROR_SUCCESS; 3861 3862 res = CoInitialize( NULL ); 3863 3864 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); 3865 msiobj_release(&view->hdr); 3866 3867 if (SUCCEEDED(res)) CoUninitialize(); 3868 return rc; 3869 } 3870 3871 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param ) 3872 { 3873 MSIPACKAGE *package = param; 3874 LPWSTR link_file; 3875 LPCWSTR component; 3876 MSICOMPONENT *comp; 3877 3878 component = MSI_RecordGetString( row, 4 ); 3879 comp = msi_get_loaded_component( package, component ); 3880 if (!comp) 3881 return ERROR_SUCCESS; 3882 3883 comp->Action = msi_get_component_action( package, comp ); 3884 if (comp->Action != INSTALLSTATE_ABSENT) 3885 { 3886 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 3887 return ERROR_SUCCESS; 3888 } 3889 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); 3890 3891 link_file = get_link_file( package, row ); 3892 TRACE("Removing shortcut file %s\n", debugstr_w( link_file )); 3893 if (!msi_delete_file( package, link_file )) WARN( "failed to remove shortcut file %lu\n", GetLastError() ); 3894 free( link_file ); 3895 3896 return ERROR_SUCCESS; 3897 } 3898 3899 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) 3900 { 3901 MSIQUERY *view; 3902 UINT rc; 3903 3904 if (package->script == SCRIPT_NONE) 3905 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveShortcuts"); 3906 3907 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Shortcut`", &view ); 3908 if (rc != ERROR_SUCCESS) 3909 return ERROR_SUCCESS; 3910 3911 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package ); 3912 msiobj_release( &view->hdr ); 3913 return rc; 3914 } 3915 3916 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param) 3917 { 3918 MSIPACKAGE *package = param; 3919 HANDLE handle; 3920 WCHAR *icon_path; 3921 const WCHAR *filename; 3922 char buffer[1024]; 3923 DWORD sz; 3924 UINT rc; 3925 3926 filename = MSI_RecordGetString( row, 1 ); 3927 if (!filename) 3928 { 3929 ERR("Unable to get filename\n"); 3930 return ERROR_SUCCESS; 3931 } 3932 3933 icon_path = msi_build_icon_path( package, filename ); 3934 3935 TRACE("Creating icon file at %s\n", debugstr_w(icon_path)); 3936 3937 handle = msi_create_file( package, icon_path, GENERIC_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL ); 3938 if (handle == INVALID_HANDLE_VALUE) 3939 { 3940 ERR("Unable to create file %s\n", debugstr_w(icon_path)); 3941 free( icon_path ); 3942 return ERROR_SUCCESS; 3943 } 3944 3945 do 3946 { 3947 DWORD count; 3948 sz = 1024; 3949 rc = MSI_RecordReadStream( row, 2, buffer, &sz ); 3950 if (rc != ERROR_SUCCESS) 3951 { 3952 ERR("Failed to get stream\n"); 3953 msi_delete_file( package, icon_path ); 3954 break; 3955 } 3956 WriteFile( handle, buffer, sz, &count, NULL ); 3957 } while (sz == 1024); 3958 3959 free( icon_path ); 3960 CloseHandle( handle ); 3961 3962 return ERROR_SUCCESS; 3963 } 3964 3965 static UINT publish_icons(MSIPACKAGE *package) 3966 { 3967 MSIQUERY *view; 3968 UINT r; 3969 3970 r = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Icon`", &view); 3971 if (r == ERROR_SUCCESS) 3972 { 3973 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package); 3974 msiobj_release(&view->hdr); 3975 if (r != ERROR_SUCCESS) 3976 return r; 3977 } 3978 return ERROR_SUCCESS; 3979 } 3980 3981 static UINT publish_sourcelist(MSIPACKAGE *package, HKEY hkey) 3982 { 3983 UINT r; 3984 HKEY source; 3985 LPWSTR buffer; 3986 MSIMEDIADISK *disk; 3987 MSISOURCELISTINFO *info; 3988 3989 r = RegCreateKeyW(hkey, L"SourceList", &source); 3990 if (r != ERROR_SUCCESS) 3991 return r; 3992 3993 RegCloseKey(source); 3994 3995 buffer = wcsrchr(package->PackagePath, '\\') + 1; 3996 r = MsiSourceListSetInfoW(package->ProductCode, NULL, 3997 package->Context, MSICODE_PRODUCT, 3998 INSTALLPROPERTY_PACKAGENAMEW, buffer); 3999 if (r != ERROR_SUCCESS) 4000 return r; 4001 4002 r = MsiSourceListSetInfoW(package->ProductCode, NULL, 4003 package->Context, MSICODE_PRODUCT, 4004 INSTALLPROPERTY_MEDIAPACKAGEPATHW, L""); 4005 if (r != ERROR_SUCCESS) 4006 return r; 4007 4008 r = MsiSourceListSetInfoW(package->ProductCode, NULL, 4009 package->Context, MSICODE_PRODUCT, 4010 INSTALLPROPERTY_DISKPROMPTW, L""); 4011 if (r != ERROR_SUCCESS) 4012 return r; 4013 4014 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry) 4015 { 4016 if (!wcscmp( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW )) 4017 msi_set_last_used_source(package->ProductCode, NULL, info->context, 4018 info->options, info->value); 4019 else 4020 MsiSourceListSetInfoW(package->ProductCode, NULL, 4021 info->context, info->options, 4022 info->property, info->value); 4023 } 4024 4025 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry) 4026 { 4027 MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 4028 disk->context, disk->options, 4029 disk->disk_id, disk->volume_label, disk->disk_prompt); 4030 } 4031 4032 return ERROR_SUCCESS; 4033 } 4034 4035 static UINT publish_product_properties(MSIPACKAGE *package, HKEY hkey) 4036 { 4037 WCHAR *buffer, *ptr, *guids, packcode[SQUASHED_GUID_SIZE]; 4038 DWORD langid; 4039 4040 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW); 4041 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer); 4042 free(buffer); 4043 4044 langid = msi_get_property_int(package->db, L"ProductLanguage", 0); 4045 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); 4046 4047 /* FIXME */ 4048 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0); 4049 4050 buffer = msi_dup_property(package->db, L"ARPPRODUCTICON"); 4051 if (buffer) 4052 { 4053 LPWSTR path = msi_build_icon_path(package, buffer); 4054 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path); 4055 free(path); 4056 free(buffer); 4057 } 4058 4059 buffer = msi_dup_property(package->db, L"ProductVersion"); 4060 if (buffer) 4061 { 4062 DWORD verdword = msi_version_str_to_dword(buffer); 4063 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); 4064 free(buffer); 4065 } 4066 4067 msi_reg_set_val_dword(hkey, L"Assignment", 0); 4068 msi_reg_set_val_dword(hkey, L"AdvertiseFlags", 0x184); 4069 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0); 4070 msi_reg_set_val_multi_str(hkey, L"Clients", L":\0"); 4071 4072 if (!(guids = msi_get_package_code(package->db))) return ERROR_OUTOFMEMORY; 4073 if ((ptr = wcschr(guids, ';'))) *ptr = 0; 4074 squash_guid(guids, packcode); 4075 free(guids); 4076 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode); 4077 4078 return ERROR_SUCCESS; 4079 } 4080 4081 static UINT publish_upgrade_code(MSIPACKAGE *package) 4082 { 4083 UINT r; 4084 HKEY hkey; 4085 WCHAR *upgrade, squashed_pc[SQUASHED_GUID_SIZE]; 4086 4087 upgrade = msi_dup_property(package->db, L"UpgradeCode"); 4088 if (!upgrade) 4089 return ERROR_SUCCESS; 4090 4091 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 4092 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE); 4093 else 4094 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE); 4095 4096 if (r != ERROR_SUCCESS) 4097 { 4098 WARN("failed to open upgrade code key\n"); 4099 free(upgrade); 4100 return ERROR_SUCCESS; 4101 } 4102 squash_guid(package->ProductCode, squashed_pc); 4103 msi_reg_set_val_str(hkey, squashed_pc, NULL); 4104 RegCloseKey(hkey); 4105 free(upgrade); 4106 return ERROR_SUCCESS; 4107 } 4108 4109 static BOOL check_publish(MSIPACKAGE *package) 4110 { 4111 MSIFEATURE *feature; 4112 4113 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) 4114 { 4115 feature->Action = msi_get_feature_action( package, feature ); 4116 if (feature->Action == INSTALLSTATE_LOCAL || feature->Action == INSTALLSTATE_SOURCE) 4117 return TRUE; 4118 } 4119 4120 return FALSE; 4121 } 4122 4123 static BOOL check_unpublish(MSIPACKAGE *package) 4124 { 4125 MSIFEATURE *feature; 4126 4127 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) 4128 { 4129 feature->Action = msi_get_feature_action( package, feature ); 4130 if (feature->Action != INSTALLSTATE_ABSENT) 4131 return FALSE; 4132 } 4133 4134 return TRUE; 4135 } 4136 4137 static UINT publish_patches( MSIPACKAGE *package ) 4138 { 4139 WCHAR patch_squashed[GUID_SIZE]; 4140 HKEY patches_key = NULL, product_patches_key = NULL, product_key; 4141 LONG res; 4142 MSIPATCHINFO *patch; 4143 UINT r; 4144 WCHAR *p, *all_patches = NULL; 4145 DWORD len = 0; 4146 4147 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE ); 4148 if (r != ERROR_SUCCESS) 4149 return ERROR_FUNCTION_FAILED; 4150 4151 res = RegCreateKeyExW( product_key, L"Patches", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL ); 4152 if (res != ERROR_SUCCESS) 4153 { 4154 r = ERROR_FUNCTION_FAILED; 4155 goto done; 4156 } 4157 4158 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE ); 4159 if (r != ERROR_SUCCESS) 4160 goto done; 4161 4162 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry ) 4163 { 4164 squash_guid( patch->patchcode, patch_squashed ); 4165 len += lstrlenW( patch_squashed ) + 1; 4166 } 4167 4168 p = all_patches = malloc( (len + 1) * sizeof(WCHAR) ); 4169 if (!all_patches) 4170 goto done; 4171 4172 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry ) 4173 { 4174 HKEY patch_key; 4175 4176 squash_guid( patch->patchcode, p ); 4177 p += lstrlenW( p ) + 1; 4178 4179 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ, 4180 (const BYTE *)patch->transforms, 4181 (lstrlenW(patch->transforms) + 1) * sizeof(WCHAR) ); 4182 if (res != ERROR_SUCCESS) 4183 goto done; 4184 4185 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE ); 4186 if (r != ERROR_SUCCESS) 4187 goto done; 4188 4189 res = RegSetValueExW( patch_key, L"LocalPackage", 0, REG_SZ, (const BYTE *)patch->localfile, 4190 (lstrlenW( patch->localfile ) + 1) * sizeof(WCHAR) ); 4191 RegCloseKey( patch_key ); 4192 if (res != ERROR_SUCCESS) 4193 goto done; 4194 4195 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE )) 4196 { 4197 res = GetLastError(); 4198 ERR( "unable to copy patch package %lu\n", res ); 4199 goto done; 4200 } 4201 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL ); 4202 if (res != ERROR_SUCCESS) 4203 goto done; 4204 4205 res = RegSetValueExW( patch_key, L"State", 0, REG_DWORD, (const BYTE *)&patch->state, 4206 sizeof(patch->state) ); 4207 if (res != ERROR_SUCCESS) 4208 { 4209 RegCloseKey( patch_key ); 4210 goto done; 4211 } 4212 4213 res = RegSetValueExW( patch_key, L"Uninstallable", 0, REG_DWORD, (const BYTE *)&patch->uninstallable, 4214 sizeof(patch->uninstallable) ); 4215 RegCloseKey( patch_key ); 4216 if (res != ERROR_SUCCESS) 4217 goto done; 4218 } 4219 4220 all_patches[len] = 0; 4221 res = RegSetValueExW( patches_key, L"Patches", 0, REG_MULTI_SZ, 4222 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) ); 4223 if (res != ERROR_SUCCESS) 4224 goto done; 4225 4226 res = RegSetValueExW( product_patches_key, L"AllPatches", 0, REG_MULTI_SZ, 4227 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) ); 4228 if (res != ERROR_SUCCESS) 4229 r = ERROR_FUNCTION_FAILED; 4230 4231 done: 4232 RegCloseKey( product_patches_key ); 4233 RegCloseKey( patches_key ); 4234 RegCloseKey( product_key ); 4235 free( all_patches ); 4236 return r; 4237 } 4238 4239 static UINT ACTION_PublishProduct(MSIPACKAGE *package) 4240 { 4241 UINT rc; 4242 HKEY hukey = NULL, hudkey = NULL; 4243 MSIRECORD *uirow; 4244 BOOL republish = FALSE; 4245 4246 if (package->script == SCRIPT_NONE) 4247 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishProduct"); 4248 4249 if (!list_empty(&package->patches)) 4250 { 4251 rc = publish_patches(package); 4252 if (rc != ERROR_SUCCESS) 4253 goto end; 4254 } 4255 4256 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context, 4257 &hukey, FALSE); 4258 if (rc == ERROR_SUCCESS) 4259 { 4260 WCHAR *package_code; 4261 4262 package_code = msi_reg_get_val_str(hukey, INSTALLPROPERTY_PACKAGECODEW); 4263 if (package_code) 4264 { 4265 WCHAR *guid; 4266 4267 guid = msi_get_package_code(package->db); 4268 if (guid) 4269 { 4270 WCHAR packed[SQUASHED_GUID_SIZE]; 4271 4272 squash_guid(guid, packed); 4273 free(guid); 4274 if (!wcscmp(packed, package_code)) 4275 { 4276 TRACE("re-publishing product - new package\n"); 4277 republish = TRUE; 4278 } 4279 } 4280 free(package_code); 4281 } 4282 } 4283 4284 /* FIXME: also need to publish if the product is in advertise mode */ 4285 if (!republish && !check_publish(package)) 4286 { 4287 if (hukey) 4288 RegCloseKey(hukey); 4289 return ERROR_SUCCESS; 4290 } 4291 4292 if (!hukey) 4293 { 4294 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context, 4295 &hukey, TRUE); 4296 if (rc != ERROR_SUCCESS) 4297 goto end; 4298 } 4299 4300 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context, 4301 NULL, &hudkey, TRUE); 4302 if (rc != ERROR_SUCCESS) 4303 goto end; 4304 4305 rc = publish_upgrade_code(package); 4306 if (rc != ERROR_SUCCESS) 4307 goto end; 4308 4309 rc = publish_product_properties(package, hukey); 4310 if (rc != ERROR_SUCCESS) 4311 goto end; 4312 4313 rc = publish_sourcelist(package, hukey); 4314 if (rc != ERROR_SUCCESS) 4315 goto end; 4316 4317 rc = publish_icons(package); 4318 4319 end: 4320 uirow = MSI_CreateRecord( 1 ); 4321 MSI_RecordSetStringW( uirow, 1, package->ProductCode ); 4322 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4323 msiobj_release( &uirow->hdr ); 4324 4325 RegCloseKey(hukey); 4326 RegCloseKey(hudkey); 4327 return rc; 4328 } 4329 4330 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row ) 4331 { 4332 WCHAR *filename, *ptr, *folder, *ret; 4333 const WCHAR *dirprop; 4334 4335 filename = msi_dup_record_field( row, 2 ); 4336 if (filename && (ptr = wcschr( filename, '|' ))) 4337 ptr++; 4338 else 4339 ptr = filename; 4340 4341 dirprop = MSI_RecordGetString( row, 3 ); 4342 if (dirprop) 4343 { 4344 folder = wcsdup( msi_get_target_folder( package, dirprop ) ); 4345 if (!folder) folder = msi_dup_property( package->db, dirprop ); 4346 } 4347 else 4348 folder = msi_dup_property( package->db, L"WindowsFolder" ); 4349 4350 if (!folder) 4351 { 4352 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop)); 4353 free( filename ); 4354 return NULL; 4355 } 4356 4357 ret = msi_build_directory_name( 2, folder, ptr ); 4358 4359 free( filename ); 4360 free( folder ); 4361 return ret; 4362 } 4363 4364 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) 4365 { 4366 MSIPACKAGE *package = param; 4367 LPCWSTR component, section, key, value, identifier; 4368 LPWSTR deformated_section, deformated_key, deformated_value, fullname; 4369 MSIRECORD * uirow; 4370 INT action; 4371 MSICOMPONENT *comp; 4372 4373 component = MSI_RecordGetString(row, 8); 4374 comp = msi_get_loaded_component(package,component); 4375 if (!comp) 4376 return ERROR_SUCCESS; 4377 4378 comp->Action = msi_get_component_action( package, comp ); 4379 if (comp->Action != INSTALLSTATE_LOCAL) 4380 { 4381 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 4382 return ERROR_SUCCESS; 4383 } 4384 4385 identifier = MSI_RecordGetString(row,1); 4386 section = MSI_RecordGetString(row,4); 4387 key = MSI_RecordGetString(row,5); 4388 value = MSI_RecordGetString(row,6); 4389 action = MSI_RecordGetInteger(row,7); 4390 4391 deformat_string(package,section,&deformated_section); 4392 deformat_string(package,key,&deformated_key); 4393 deformat_string(package,value,&deformated_value); 4394 4395 fullname = get_ini_file_name(package, row); 4396 4397 if (action == 0) 4398 { 4399 TRACE("Adding value %s to section %s in %s\n", 4400 debugstr_w(deformated_key), debugstr_w(deformated_section), 4401 debugstr_w(fullname)); 4402 WritePrivateProfileStringW(deformated_section, deformated_key, 4403 deformated_value, fullname); 4404 } 4405 else if (action == 1) 4406 { 4407 WCHAR returned[10]; 4408 GetPrivateProfileStringW(deformated_section, deformated_key, NULL, 4409 returned, 10, fullname); 4410 if (returned[0] == 0) 4411 { 4412 TRACE("Adding value %s to section %s in %s\n", 4413 debugstr_w(deformated_key), debugstr_w(deformated_section), 4414 debugstr_w(fullname)); 4415 4416 WritePrivateProfileStringW(deformated_section, deformated_key, 4417 deformated_value, fullname); 4418 } 4419 } 4420 else if (action == 3) 4421 FIXME("Append to existing section not yet implemented\n"); 4422 4423 uirow = MSI_CreateRecord(4); 4424 MSI_RecordSetStringW(uirow,1,identifier); 4425 MSI_RecordSetStringW(uirow,2,deformated_section); 4426 MSI_RecordSetStringW(uirow,3,deformated_key); 4427 MSI_RecordSetStringW(uirow,4,deformated_value); 4428 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4429 msiobj_release( &uirow->hdr ); 4430 4431 free(fullname); 4432 free(deformated_key); 4433 free(deformated_value); 4434 free(deformated_section); 4435 return ERROR_SUCCESS; 4436 } 4437 4438 static UINT ACTION_WriteIniValues(MSIPACKAGE *package) 4439 { 4440 MSIQUERY *view; 4441 UINT rc; 4442 4443 if (package->script == SCRIPT_NONE) 4444 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteIniValues"); 4445 4446 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `IniFile`", &view); 4447 if (rc != ERROR_SUCCESS) 4448 return ERROR_SUCCESS; 4449 4450 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package); 4451 msiobj_release(&view->hdr); 4452 return rc; 4453 } 4454 4455 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param ) 4456 { 4457 MSIPACKAGE *package = param; 4458 LPCWSTR component, section, key, value, identifier; 4459 LPWSTR deformated_section, deformated_key, deformated_value, filename; 4460 MSICOMPONENT *comp; 4461 MSIRECORD *uirow; 4462 INT action; 4463 4464 component = MSI_RecordGetString( row, 8 ); 4465 comp = msi_get_loaded_component( package, component ); 4466 if (!comp) 4467 return ERROR_SUCCESS; 4468 4469 comp->Action = msi_get_component_action( package, comp ); 4470 if (comp->Action != INSTALLSTATE_ABSENT) 4471 { 4472 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 4473 return ERROR_SUCCESS; 4474 } 4475 4476 identifier = MSI_RecordGetString( row, 1 ); 4477 section = MSI_RecordGetString( row, 4 ); 4478 key = MSI_RecordGetString( row, 5 ); 4479 value = MSI_RecordGetString( row, 6 ); 4480 action = MSI_RecordGetInteger( row, 7 ); 4481 4482 deformat_string( package, section, &deformated_section ); 4483 deformat_string( package, key, &deformated_key ); 4484 deformat_string( package, value, &deformated_value ); 4485 4486 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine) 4487 { 4488 filename = get_ini_file_name( package, row ); 4489 4490 TRACE("Removing key %s from section %s in %s\n", 4491 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename)); 4492 4493 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename )) 4494 { 4495 WARN( "unable to remove key %lu\n", GetLastError() ); 4496 } 4497 free( filename ); 4498 } 4499 else 4500 FIXME("Unsupported action %d\n", action); 4501 4502 4503 uirow = MSI_CreateRecord( 4 ); 4504 MSI_RecordSetStringW( uirow, 1, identifier ); 4505 MSI_RecordSetStringW( uirow, 2, deformated_section ); 4506 MSI_RecordSetStringW( uirow, 3, deformated_key ); 4507 MSI_RecordSetStringW( uirow, 4, deformated_value ); 4508 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4509 msiobj_release( &uirow->hdr ); 4510 4511 free( deformated_key ); 4512 free( deformated_value ); 4513 free( deformated_section ); 4514 return ERROR_SUCCESS; 4515 } 4516 4517 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param ) 4518 { 4519 MSIPACKAGE *package = param; 4520 LPCWSTR component, section, key, value, identifier; 4521 LPWSTR deformated_section, deformated_key, deformated_value, filename; 4522 MSICOMPONENT *comp; 4523 MSIRECORD *uirow; 4524 INT action; 4525 4526 component = MSI_RecordGetString( row, 8 ); 4527 comp = msi_get_loaded_component( package, component ); 4528 if (!comp) 4529 return ERROR_SUCCESS; 4530 4531 comp->Action = msi_get_component_action( package, comp ); 4532 if (comp->Action != INSTALLSTATE_LOCAL) 4533 { 4534 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 4535 return ERROR_SUCCESS; 4536 } 4537 4538 identifier = MSI_RecordGetString( row, 1 ); 4539 section = MSI_RecordGetString( row, 4 ); 4540 key = MSI_RecordGetString( row, 5 ); 4541 value = MSI_RecordGetString( row, 6 ); 4542 action = MSI_RecordGetInteger( row, 7 ); 4543 4544 deformat_string( package, section, &deformated_section ); 4545 deformat_string( package, key, &deformated_key ); 4546 deformat_string( package, value, &deformated_value ); 4547 4548 if (action == msidbIniFileActionRemoveLine) 4549 { 4550 filename = get_ini_file_name( package, row ); 4551 4552 TRACE("Removing key %s from section %s in %s\n", 4553 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename)); 4554 4555 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename )) 4556 { 4557 WARN( "unable to remove key %lu\n", GetLastError() ); 4558 } 4559 free( filename ); 4560 } 4561 else 4562 FIXME("Unsupported action %d\n", action); 4563 4564 uirow = MSI_CreateRecord( 4 ); 4565 MSI_RecordSetStringW( uirow, 1, identifier ); 4566 MSI_RecordSetStringW( uirow, 2, deformated_section ); 4567 MSI_RecordSetStringW( uirow, 3, deformated_key ); 4568 MSI_RecordSetStringW( uirow, 4, deformated_value ); 4569 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4570 msiobj_release( &uirow->hdr ); 4571 4572 free( deformated_key ); 4573 free( deformated_value ); 4574 free( deformated_section ); 4575 return ERROR_SUCCESS; 4576 } 4577 4578 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package ) 4579 { 4580 MSIQUERY *view; 4581 UINT rc; 4582 4583 if (package->script == SCRIPT_NONE) 4584 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveIniValues"); 4585 4586 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `IniFile`", &view ); 4587 if (rc == ERROR_SUCCESS) 4588 { 4589 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package ); 4590 msiobj_release( &view->hdr ); 4591 if (rc != ERROR_SUCCESS) 4592 return rc; 4593 } 4594 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveIniFile`", &view ); 4595 if (rc == ERROR_SUCCESS) 4596 { 4597 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package ); 4598 msiobj_release( &view->hdr ); 4599 if (rc != ERROR_SUCCESS) 4600 return rc; 4601 } 4602 return ERROR_SUCCESS; 4603 } 4604 4605 static void register_dll( const WCHAR *dll, BOOL unregister ) 4606 { 4607 static const WCHAR regW[] = L"regsvr32.exe /s \"%s\""; 4608 static const WCHAR unregW[] = L"regsvr32.exe /s /u \"%s\""; 4609 PROCESS_INFORMATION pi; 4610 STARTUPINFOW si; 4611 WCHAR *cmd; 4612 4613 if (!(cmd = malloc( wcslen(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return; 4614 4615 if (unregister) swprintf( cmd, lstrlenW(dll) + ARRAY_SIZE(unregW), unregW, dll ); 4616 else swprintf( cmd, lstrlenW(dll) + ARRAY_SIZE(unregW), regW, dll ); 4617 4618 memset( &si, 0, sizeof(STARTUPINFOW) ); 4619 if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi )) 4620 { 4621 CloseHandle( pi.hThread ); 4622 msi_dialog_check_messages( pi.hProcess ); 4623 CloseHandle( pi.hProcess ); 4624 } 4625 free( cmd ); 4626 } 4627 4628 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param) 4629 { 4630 MSIPACKAGE *package = param; 4631 LPCWSTR filename; 4632 MSIFILE *file; 4633 MSIRECORD *uirow; 4634 4635 filename = MSI_RecordGetString( row, 1 ); 4636 file = msi_get_loaded_file( package, filename ); 4637 if (!file) 4638 { 4639 WARN("unable to find file %s\n", debugstr_w(filename)); 4640 return ERROR_SUCCESS; 4641 } 4642 file->Component->Action = msi_get_component_action( package, file->Component ); 4643 if (file->Component->Action != INSTALLSTATE_LOCAL) 4644 { 4645 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component)); 4646 return ERROR_SUCCESS; 4647 } 4648 4649 TRACE("Registering %s\n", debugstr_w( file->TargetPath )); 4650 register_dll( file->TargetPath, FALSE ); 4651 4652 uirow = MSI_CreateRecord( 2 ); 4653 MSI_RecordSetStringW( uirow, 1, file->File ); 4654 MSI_RecordSetStringW( uirow, 2, file->Component->Directory ); 4655 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4656 msiobj_release( &uirow->hdr ); 4657 4658 return ERROR_SUCCESS; 4659 } 4660 4661 static UINT ACTION_SelfRegModules(MSIPACKAGE *package) 4662 { 4663 MSIQUERY *view; 4664 UINT rc; 4665 4666 if (package->script == SCRIPT_NONE) 4667 return msi_schedule_action(package, SCRIPT_INSTALL, L"SelfRegModules"); 4668 4669 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `SelfReg`", &view); 4670 if (rc != ERROR_SUCCESS) 4671 return ERROR_SUCCESS; 4672 4673 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package); 4674 msiobj_release(&view->hdr); 4675 return rc; 4676 } 4677 4678 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param ) 4679 { 4680 MSIPACKAGE *package = param; 4681 LPCWSTR filename; 4682 MSIFILE *file; 4683 MSIRECORD *uirow; 4684 4685 filename = MSI_RecordGetString( row, 1 ); 4686 file = msi_get_loaded_file( package, filename ); 4687 if (!file) 4688 { 4689 WARN("unable to find file %s\n", debugstr_w(filename)); 4690 return ERROR_SUCCESS; 4691 } 4692 file->Component->Action = msi_get_component_action( package, file->Component ); 4693 if (file->Component->Action != INSTALLSTATE_ABSENT) 4694 { 4695 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component)); 4696 return ERROR_SUCCESS; 4697 } 4698 4699 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath )); 4700 register_dll( file->TargetPath, TRUE ); 4701 4702 uirow = MSI_CreateRecord( 2 ); 4703 MSI_RecordSetStringW( uirow, 1, file->File ); 4704 MSI_RecordSetStringW( uirow, 2, file->Component->Directory ); 4705 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4706 msiobj_release( &uirow->hdr ); 4707 4708 return ERROR_SUCCESS; 4709 } 4710 4711 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) 4712 { 4713 MSIQUERY *view; 4714 UINT rc; 4715 4716 if (package->script == SCRIPT_NONE) 4717 return msi_schedule_action(package, SCRIPT_INSTALL, L"SelfUnregModules"); 4718 4719 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `SelfReg`", &view ); 4720 if (rc != ERROR_SUCCESS) 4721 return ERROR_SUCCESS; 4722 4723 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package ); 4724 msiobj_release( &view->hdr ); 4725 return rc; 4726 } 4727 4728 static UINT ACTION_PublishFeatures(MSIPACKAGE *package) 4729 { 4730 MSIFEATURE *feature; 4731 UINT rc; 4732 HKEY hkey = NULL, userdata = NULL; 4733 4734 if (package->script == SCRIPT_NONE) 4735 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishFeatures"); 4736 4737 if (!check_publish(package)) 4738 return ERROR_SUCCESS; 4739 4740 rc = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context, 4741 &hkey, TRUE); 4742 if (rc != ERROR_SUCCESS) 4743 goto end; 4744 4745 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context, 4746 &userdata, TRUE); 4747 if (rc != ERROR_SUCCESS) 4748 goto end; 4749 4750 /* here the guids are base 85 encoded */ 4751 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 4752 { 4753 ComponentList *cl; 4754 LPWSTR data = NULL; 4755 GUID clsid; 4756 INT size; 4757 BOOL absent = FALSE; 4758 MSIRECORD *uirow; 4759 4760 if (feature->Level <= 0) continue; 4761 if (feature->Action == INSTALLSTATE_UNKNOWN && 4762 feature->Installed != INSTALLSTATE_ABSENT) continue; 4763 4764 if (feature->Action != INSTALLSTATE_LOCAL && 4765 feature->Action != INSTALLSTATE_SOURCE && 4766 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE; 4767 4768 size = 1; 4769 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 4770 { 4771 size += 21; 4772 } 4773 if (feature->Feature_Parent) 4774 size += lstrlenW( feature->Feature_Parent )+2; 4775 4776 data = malloc(size * sizeof(WCHAR)); 4777 4778 data[0] = 0; 4779 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 4780 { 4781 MSICOMPONENT* component = cl->component; 4782 WCHAR buf[21]; 4783 4784 buf[0] = 0; 4785 if (component->ComponentId) 4786 { 4787 TRACE("From %s\n",debugstr_w(component->ComponentId)); 4788 CLSIDFromString(component->ComponentId, &clsid); 4789 encode_base85_guid(&clsid,buf); 4790 TRACE("to %s\n",debugstr_w(buf)); 4791 lstrcatW(data,buf); 4792 } 4793 } 4794 4795 if (feature->Feature_Parent) 4796 { 4797 lstrcatW(data, L"\2"); 4798 lstrcatW(data, feature->Feature_Parent); 4799 } 4800 4801 msi_reg_set_val_str( userdata, feature->Feature, data ); 4802 free(data); 4803 4804 size = 0; 4805 if (feature->Feature_Parent) 4806 size = lstrlenW(feature->Feature_Parent)*sizeof(WCHAR); 4807 if (!absent) 4808 { 4809 size += sizeof(WCHAR); 4810 RegSetValueExW(hkey, feature->Feature, 0 ,REG_SZ, 4811 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : L""), size); 4812 } 4813 else 4814 { 4815 size += 2*sizeof(WCHAR); 4816 data = malloc(size); 4817 data[0] = 0x6; 4818 data[1] = 0; 4819 if (feature->Feature_Parent) 4820 lstrcpyW( &data[1], feature->Feature_Parent ); 4821 RegSetValueExW(hkey,feature->Feature,0,REG_SZ, 4822 (LPBYTE)data,size); 4823 free(data); 4824 } 4825 4826 /* the UI chunk */ 4827 uirow = MSI_CreateRecord( 1 ); 4828 MSI_RecordSetStringW( uirow, 1, feature->Feature ); 4829 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4830 msiobj_release( &uirow->hdr ); 4831 /* FIXME: call msi_ui_progress? */ 4832 } 4833 4834 end: 4835 RegCloseKey(hkey); 4836 RegCloseKey(userdata); 4837 return rc; 4838 } 4839 4840 static UINT unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature) 4841 { 4842 UINT r; 4843 HKEY hkey; 4844 MSIRECORD *uirow; 4845 4846 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature)); 4847 4848 r = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context, 4849 &hkey, FALSE); 4850 if (r == ERROR_SUCCESS) 4851 { 4852 RegDeleteValueW(hkey, feature->Feature); 4853 RegCloseKey(hkey); 4854 } 4855 4856 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context, 4857 &hkey, FALSE); 4858 if (r == ERROR_SUCCESS) 4859 { 4860 RegDeleteValueW(hkey, feature->Feature); 4861 RegCloseKey(hkey); 4862 } 4863 4864 uirow = MSI_CreateRecord( 1 ); 4865 MSI_RecordSetStringW( uirow, 1, feature->Feature ); 4866 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 4867 msiobj_release( &uirow->hdr ); 4868 4869 return ERROR_SUCCESS; 4870 } 4871 4872 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package) 4873 { 4874 MSIFEATURE *feature; 4875 4876 if (package->script == SCRIPT_NONE) 4877 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnpublishFeatures"); 4878 4879 if (!check_unpublish(package)) 4880 return ERROR_SUCCESS; 4881 4882 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) 4883 { 4884 unpublish_feature(package, feature); 4885 } 4886 4887 return ERROR_SUCCESS; 4888 } 4889 4890 static UINT publish_install_properties(MSIPACKAGE *package, HKEY hkey) 4891 { 4892 static const WCHAR *propval[] = 4893 { 4894 L"ARPAUTHORIZEDCDFPREFIX", L"AuthorizedCDFPrefix", 4895 L"ARPCONTACT", L"Contact", 4896 L"ARPCOMMENTS", L"Comments", 4897 L"ProductName", L"DisplayName", 4898 L"ARPHELPLINK", L"HelpLink", 4899 L"ARPHELPTELEPHONE", L"HelpTelephone", 4900 L"ARPINSTALLLOCATION", L"InstallLocation", 4901 L"SourceDir", L"InstallSource", 4902 L"Manufacturer", L"Publisher", 4903 L"ARPREADME", L"ReadMe", 4904 L"ARPSIZE", L"Size", 4905 L"ARPURLINFOABOUT", L"URLInfoAbout", 4906 L"ARPURLUPDATEINFO", L"URLUpdateInfo", 4907 NULL 4908 }; 4909 const WCHAR **p = propval; 4910 SYSTEMTIME systime; 4911 DWORD size, langid; 4912 WCHAR date[9], *val, *buffer; 4913 const WCHAR *prop, *key; 4914 4915 while (*p) 4916 { 4917 prop = *p++; 4918 key = *p++; 4919 val = msi_dup_property(package->db, prop); 4920 msi_reg_set_val_str(hkey, key, val); 4921 free(val); 4922 } 4923 4924 msi_reg_set_val_dword(hkey, L"WindowsInstaller", 1); 4925 if (msi_get_property_int( package->db, L"ARPSYSTEMCOMPONENT", 0 )) 4926 { 4927 msi_reg_set_val_dword( hkey, L"SystemComponent", 1 ); 4928 } 4929 4930 if (msi_get_property_int( package->db, L"ARPNOREMOVE", 0 )) 4931 msi_reg_set_val_dword( hkey, L"NoRemove", 1 ); 4932 else 4933 { 4934 static const WCHAR fmt_install[] = L"MsiExec.exe /I[ProductCode]"; 4935 static const WCHAR fmt_uninstall[] = L"MsiExec.exe /X[ProductCode]"; 4936 const WCHAR *fmt = fmt_install; 4937 4938 if (msi_get_property_int( package->db, L"ARPNOREPAIR", 0 )) 4939 msi_reg_set_val_dword( hkey, L"NoRepair", 1 ); 4940 4941 if (msi_get_property_int( package->db, L"ARPNOMODIFY", 0 )) 4942 { 4943 msi_reg_set_val_dword( hkey, L"NoModify", 1 ); 4944 fmt = fmt_uninstall; 4945 } 4946 4947 size = deformat_string(package, fmt, &buffer) * sizeof(WCHAR); 4948 RegSetValueExW(hkey, L"ModifyPath", 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); 4949 RegSetValueExW(hkey, L"UninstallString", 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); 4950 free(buffer); 4951 } 4952 4953 /* FIXME: Write real Estimated Size when we have it */ 4954 msi_reg_set_val_dword(hkey, L"EstimatedSize", 0); 4955 4956 GetLocalTime(&systime); 4957 swprintf(date, ARRAY_SIZE(date), L"%d%02d%02d", systime.wYear, systime.wMonth, systime.wDay); 4958 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date); 4959 4960 langid = msi_get_property_int(package->db, L"ProductLanguage", 0); 4961 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); 4962 4963 buffer = msi_dup_property(package->db, L"ProductVersion"); 4964 msi_reg_set_val_str(hkey, L"DisplayVersion", buffer); 4965 if (buffer) 4966 { 4967 DWORD verdword = msi_version_str_to_dword(buffer); 4968 4969 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); 4970 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24); 4971 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF); 4972 free(buffer); 4973 } 4974 4975 return ERROR_SUCCESS; 4976 } 4977 4978 static UINT ACTION_RegisterProduct(MSIPACKAGE *package) 4979 { 4980 WCHAR *upgrade_code, squashed_pc[SQUASHED_GUID_SIZE]; 4981 MSIRECORD *uirow; 4982 HKEY hkey, props, upgrade_key; 4983 UINT rc; 4984 4985 if (package->script == SCRIPT_NONE) 4986 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterProduct"); 4987 4988 /* FIXME: also need to publish if the product is in advertise mode */ 4989 if (!msi_get_property_int( package->db, L"ProductToBeRegistered", 0 ) && !check_publish(package)) 4990 return ERROR_SUCCESS; 4991 4992 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE); 4993 if (rc != ERROR_SUCCESS) 4994 return rc; 4995 4996 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE); 4997 if (rc != ERROR_SUCCESS) 4998 goto done; 4999 5000 rc = publish_install_properties(package, hkey); 5001 if (rc != ERROR_SUCCESS) 5002 goto done; 5003 5004 rc = publish_install_properties(package, props); 5005 if (rc != ERROR_SUCCESS) 5006 goto done; 5007 5008 upgrade_code = msi_dup_property(package->db, L"UpgradeCode"); 5009 if (upgrade_code) 5010 { 5011 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE ); 5012 if (rc == ERROR_SUCCESS) 5013 { 5014 squash_guid( package->ProductCode, squashed_pc ); 5015 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL ); 5016 RegCloseKey( upgrade_key ); 5017 } 5018 free( upgrade_code ); 5019 } 5020 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile ); 5021 package->delete_on_close = FALSE; 5022 5023 done: 5024 uirow = MSI_CreateRecord( 1 ); 5025 MSI_RecordSetStringW( uirow, 1, package->ProductCode ); 5026 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 5027 msiobj_release( &uirow->hdr ); 5028 5029 RegCloseKey(hkey); 5030 return ERROR_SUCCESS; 5031 } 5032 5033 static UINT ACTION_InstallExecute(MSIPACKAGE *package) 5034 { 5035 return execute_script(package, SCRIPT_INSTALL); 5036 } 5037 5038 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param ) 5039 { 5040 MSIPACKAGE *package = param; 5041 const WCHAR *icon = MSI_RecordGetString( row, 1 ); 5042 WCHAR *p, *icon_path; 5043 5044 if (!icon) return ERROR_SUCCESS; 5045 if ((icon_path = msi_build_icon_path( package, icon ))) 5046 { 5047 TRACE("removing icon file %s\n", debugstr_w(icon_path)); 5048 msi_delete_file( package, icon_path ); 5049 if ((p = wcsrchr( icon_path, '\\' ))) 5050 { 5051 *p = 0; 5052 msi_remove_directory( package, icon_path ); 5053 } 5054 free( icon_path ); 5055 } 5056 return ERROR_SUCCESS; 5057 } 5058 5059 static UINT unpublish_icons( MSIPACKAGE *package ) 5060 { 5061 MSIQUERY *view; 5062 UINT r; 5063 5064 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Icon`", &view ); 5065 if (r == ERROR_SUCCESS) 5066 { 5067 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package ); 5068 msiobj_release( &view->hdr ); 5069 if (r != ERROR_SUCCESS) 5070 return r; 5071 } 5072 return ERROR_SUCCESS; 5073 } 5074 5075 static void remove_product_upgrade_code( MSIPACKAGE *package ) 5076 { 5077 WCHAR *code, product[SQUASHED_GUID_SIZE]; 5078 HKEY hkey; 5079 LONG res; 5080 DWORD count; 5081 5082 squash_guid( package->ProductCode, product ); 5083 if (!(code = msi_dup_property( package->db, L"UpgradeCode" ))) 5084 { 5085 WARN( "upgrade code not found\n" ); 5086 return; 5087 } 5088 if (!MSIREG_OpenUpgradeCodesKey( code, &hkey, FALSE )) 5089 { 5090 RegDeleteValueW( hkey, product ); 5091 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL ); 5092 RegCloseKey( hkey ); 5093 if (!res && !count) MSIREG_DeleteUpgradeCodesKey( code ); 5094 } 5095 if (!MSIREG_OpenUserUpgradeCodesKey( code, &hkey, FALSE )) 5096 { 5097 RegDeleteValueW( hkey, product ); 5098 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL ); 5099 RegCloseKey( hkey ); 5100 if (!res && !count) MSIREG_DeleteUserUpgradeCodesKey( code ); 5101 } 5102 if (!MSIREG_OpenClassesUpgradeCodesKey( code, &hkey, FALSE )) 5103 { 5104 RegDeleteValueW( hkey, product ); 5105 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL ); 5106 RegCloseKey( hkey ); 5107 if (!res && !count) MSIREG_DeleteClassesUpgradeCodesKey( code ); 5108 } 5109 5110 free( code ); 5111 } 5112 5113 static UINT ACTION_UnpublishProduct(MSIPACKAGE *package) 5114 { 5115 MSIPATCHINFO *patch; 5116 5117 MSIREG_DeleteProductKey(package->ProductCode); 5118 MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context); 5119 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform); 5120 5121 MSIREG_DeleteLocalClassesProductKey(package->ProductCode); 5122 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode); 5123 MSIREG_DeleteUserProductKey(package->ProductCode); 5124 MSIREG_DeleteUserFeaturesKey(package->ProductCode); 5125 5126 remove_product_upgrade_code( package ); 5127 5128 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry) 5129 { 5130 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context); 5131 if (!wcscmp( package->ProductCode, patch->products )) 5132 { 5133 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile)); 5134 patch->delete_on_close = TRUE; 5135 } 5136 /* FIXME: remove local patch package if this is the last product */ 5137 } 5138 TRACE("removing local package %s\n", debugstr_w(package->localfile)); 5139 package->delete_on_close = TRUE; 5140 5141 unpublish_icons( package ); 5142 return ERROR_SUCCESS; 5143 } 5144 5145 static BOOL is_full_uninstall( MSIPACKAGE *package ) 5146 { 5147 MSIFEATURE *feature; 5148 5149 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 5150 { 5151 if (feature->Action != INSTALLSTATE_ABSENT && 5152 (feature->Installed != INSTALLSTATE_ABSENT || feature->Action != INSTALLSTATE_UNKNOWN)) 5153 return FALSE; 5154 } 5155 5156 return TRUE; 5157 } 5158 5159 static UINT ACTION_InstallFinalize(MSIPACKAGE *package) 5160 { 5161 UINT rc; 5162 MSIFILE *file; 5163 MSIFILEPATCH *patch; 5164 5165 /* first do the same as an InstallExecute */ 5166 rc = execute_script(package, SCRIPT_INSTALL); 5167 if (rc != ERROR_SUCCESS) 5168 return rc; 5169 5170 /* install global assemblies */ 5171 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 5172 { 5173 MSICOMPONENT *comp = file->Component; 5174 5175 if (!msi_is_global_assembly( comp ) || (file->state != msifs_missing && file->state != msifs_overwrite)) 5176 continue; 5177 5178 rc = msi_install_assembly( package, comp ); 5179 if (rc != ERROR_SUCCESS) 5180 { 5181 ERR("Failed to install assembly\n"); 5182 return ERROR_INSTALL_FAILURE; 5183 } 5184 file->state = msifs_installed; 5185 } 5186 5187 /* patch global assemblies */ 5188 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) 5189 { 5190 MSICOMPONENT *comp = patch->File->Component; 5191 5192 if (!msi_is_global_assembly( comp ) || !patch->path) continue; 5193 5194 rc = msi_patch_assembly( package, comp->assembly, patch ); 5195 if (rc && !(patch->Attributes & msidbPatchAttributesNonVital)) 5196 { 5197 ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File)); 5198 return rc; 5199 } 5200 5201 if ((rc = msi_install_assembly( package, comp ))) 5202 { 5203 ERR("Failed to install patched assembly\n"); 5204 return rc; 5205 } 5206 } 5207 5208 /* then handle commit actions */ 5209 rc = execute_script(package, SCRIPT_COMMIT); 5210 if (rc != ERROR_SUCCESS) 5211 return rc; 5212 5213 if (is_full_uninstall(package)) 5214 rc = ACTION_UnpublishProduct(package); 5215 5216 return rc; 5217 } 5218 5219 UINT ACTION_ForceReboot(MSIPACKAGE *package) 5220 { 5221 WCHAR buffer[256], sysdir[MAX_PATH], squashed_pc[SQUASHED_GUID_SIZE]; 5222 HKEY hkey; 5223 5224 squash_guid( package->ProductCode, squashed_pc ); 5225 5226 GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir)); 5227 RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", &hkey); 5228 swprintf(buffer, ARRAY_SIZE(buffer), L"%s\\MsiExec.exe /@ \"%s\"", sysdir, squashed_pc); 5229 5230 msi_reg_set_val_str( hkey, squashed_pc, buffer ); 5231 RegCloseKey(hkey); 5232 5233 TRACE("Reboot command %s\n",debugstr_w(buffer)); 5234 5235 RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\RunOnceEntries", 5236 &hkey); 5237 swprintf( buffer, ARRAY_SIZE(buffer), L"/I \"%s\" AFTERREBOOT=1 RUNONCEENTRY=\"%s\"", package->ProductCode, 5238 squashed_pc ); 5239 5240 msi_reg_set_val_str( hkey, squashed_pc, buffer ); 5241 RegCloseKey(hkey); 5242 5243 return ERROR_INSTALL_SUSPEND; 5244 } 5245 5246 static UINT ACTION_ResolveSource(MSIPACKAGE* package) 5247 { 5248 DWORD attrib; 5249 UINT rc; 5250 5251 /* 5252 * We are currently doing what should be done here in the top level Install 5253 * however for Administrative and uninstalls this step will be needed 5254 */ 5255 if (!package->PackagePath) 5256 return ERROR_SUCCESS; 5257 5258 msi_set_sourcedir_props(package, TRUE); 5259 5260 attrib = GetFileAttributesW(package->db->path); 5261 if (attrib == INVALID_FILE_ATTRIBUTES) 5262 { 5263 MSIRECORD *record; 5264 LPWSTR prompt; 5265 DWORD size = 0; 5266 5267 rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 5268 package->Context, MSICODE_PRODUCT, 5269 INSTALLPROPERTY_DISKPROMPTW,NULL,&size); 5270 if (rc == ERROR_MORE_DATA) 5271 { 5272 prompt = malloc(size * sizeof(WCHAR)); 5273 MsiSourceListGetInfoW(package->ProductCode, NULL, 5274 package->Context, MSICODE_PRODUCT, 5275 INSTALLPROPERTY_DISKPROMPTW,prompt,&size); 5276 } 5277 else 5278 prompt = wcsdup(package->db->path); 5279 5280 record = MSI_CreateRecord(2); 5281 MSI_RecordSetInteger(record, 1, MSIERR_INSERTDISK); 5282 MSI_RecordSetStringW(record, 2, prompt); 5283 free(prompt); 5284 while(attrib == INVALID_FILE_ATTRIBUTES) 5285 { 5286 MSI_RecordSetStringW(record, 0, NULL); 5287 rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ERROR, record); 5288 if (rc == IDCANCEL) 5289 { 5290 msiobj_release(&record->hdr); 5291 return ERROR_INSTALL_USEREXIT; 5292 } 5293 attrib = GetFileAttributesW(package->db->path); 5294 } 5295 msiobj_release(&record->hdr); 5296 rc = ERROR_SUCCESS; 5297 } 5298 else 5299 return ERROR_SUCCESS; 5300 5301 return rc; 5302 } 5303 5304 static UINT ACTION_RegisterUser(MSIPACKAGE *package) 5305 { 5306 static const WCHAR szPropKeys[][80] = 5307 { 5308 L"ProductID", 5309 L"USERNAME", 5310 L"COMPANYNAME", 5311 L"", 5312 }; 5313 static const WCHAR szRegKeys[][80] = 5314 { 5315 L"ProductID", 5316 L"RegOwner", 5317 L"RegCompany", 5318 L"", 5319 }; 5320 HKEY hkey = 0; 5321 LPWSTR buffer, productid = NULL; 5322 UINT i, rc = ERROR_SUCCESS; 5323 MSIRECORD *uirow; 5324 5325 if (package->script == SCRIPT_NONE) 5326 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterUser"); 5327 5328 if (check_unpublish(package)) 5329 { 5330 MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context); 5331 goto end; 5332 } 5333 5334 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW ); 5335 if (!productid) 5336 goto end; 5337 5338 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, 5339 NULL, &hkey, TRUE); 5340 if (rc != ERROR_SUCCESS) 5341 goto end; 5342 5343 for( i = 0; szPropKeys[i][0]; i++ ) 5344 { 5345 buffer = msi_dup_property( package->db, szPropKeys[i] ); 5346 msi_reg_set_val_str( hkey, szRegKeys[i], buffer ); 5347 free( buffer ); 5348 } 5349 5350 end: 5351 uirow = MSI_CreateRecord( 1 ); 5352 MSI_RecordSetStringW( uirow, 1, productid ); 5353 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 5354 msiobj_release( &uirow->hdr ); 5355 5356 free(productid); 5357 RegCloseKey(hkey); 5358 return rc; 5359 } 5360 5361 static UINT iterate_properties(MSIRECORD *record, void *param) 5362 { 5363 MSIRECORD *uirow; 5364 5365 uirow = MSI_CloneRecord(record); 5366 if (!uirow) return ERROR_OUTOFMEMORY; 5367 MSI_RecordSetStringW(uirow, 0, L"Property(S): [1] = [2]"); 5368 MSI_ProcessMessage(param, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow); 5369 msiobj_release(&uirow->hdr); 5370 5371 return ERROR_SUCCESS; 5372 } 5373 5374 5375 static UINT ACTION_ExecuteAction(MSIPACKAGE *package) 5376 { 5377 WCHAR *productname; 5378 WCHAR *action; 5379 WCHAR *info_template; 5380 MSIQUERY *view; 5381 MSIRECORD *uirow, *uirow_info; 5382 UINT rc; 5383 5384 /* Send COMMONDATA and INFO messages. */ 5385 /* FIXME: when should these messages be sent? [see also MsiOpenPackage()] */ 5386 uirow = MSI_CreateRecord(3); 5387 if (!uirow) return ERROR_OUTOFMEMORY; 5388 MSI_RecordSetStringW(uirow, 0, NULL); 5389 MSI_RecordSetInteger(uirow, 1, 0); 5390 MSI_RecordSetInteger(uirow, 2, package->num_langids ? package->langids[0] : 0); 5391 MSI_RecordSetInteger(uirow, 3, msi_get_string_table_codepage(package->db->strings)); 5392 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow); 5393 /* FIXME: send INSTALLMESSAGE_PROGRESS */ 5394 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow); 5395 5396 if (!(needs_ui_sequence(package) && ui_sequence_exists(package))) 5397 { 5398 uirow_info = MSI_CreateRecord(0); 5399 if (!uirow_info) 5400 { 5401 msiobj_release(&uirow->hdr); 5402 return ERROR_OUTOFMEMORY; 5403 } 5404 info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART); 5405 MSI_RecordSetStringW(uirow_info, 0, info_template); 5406 free(info_template); 5407 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow_info); 5408 msiobj_release(&uirow_info->hdr); 5409 } 5410 5411 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow); 5412 5413 productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW); 5414 MSI_RecordSetInteger(uirow, 1, 1); 5415 MSI_RecordSetStringW(uirow, 2, productname); 5416 MSI_RecordSetStringW(uirow, 3, NULL); 5417 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow); 5418 msiobj_release(&uirow->hdr); 5419 5420 package->LastActionResult = MSI_NULL_INTEGER; 5421 5422 action = msi_dup_property(package->db, L"EXECUTEACTION"); 5423 if (!action) action = msi_strdupW(L"INSTALL", ARRAY_SIZE(L"INSTALL") - 1); 5424 5425 /* Perform the action. Top-level actions trigger a sequence. */ 5426 if (!wcscmp(action, L"INSTALL")) 5427 { 5428 /* Send ACTIONSTART/INFO and INSTALLSTART. */ 5429 ui_actionstart(package, L"INSTALL", NULL, NULL); 5430 ui_actioninfo(package, L"INSTALL", TRUE, 0); 5431 uirow = MSI_CreateRecord(2); 5432 if (!uirow) 5433 { 5434 rc = ERROR_OUTOFMEMORY; 5435 goto end; 5436 } 5437 MSI_RecordSetStringW(uirow, 0, NULL); 5438 MSI_RecordSetStringW(uirow, 1, productname); 5439 MSI_RecordSetStringW(uirow, 2, package->ProductCode); 5440 MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLSTART, uirow); 5441 msiobj_release(&uirow->hdr); 5442 5443 /* Perform the installation. Always use the ExecuteSequence. */ 5444 package->InWhatSequence |= SEQUENCE_EXEC; 5445 rc = ACTION_ProcessExecSequence(package); 5446 5447 /* Send return value and INSTALLEND. */ 5448 ui_actioninfo(package, L"INSTALL", FALSE, !rc); 5449 uirow = MSI_CreateRecord(3); 5450 if (!uirow) 5451 { 5452 rc = ERROR_OUTOFMEMORY; 5453 goto end; 5454 } 5455 MSI_RecordSetStringW(uirow, 0, NULL); 5456 MSI_RecordSetStringW(uirow, 1, productname); 5457 MSI_RecordSetStringW(uirow, 2, package->ProductCode); 5458 MSI_RecordSetInteger(uirow, 3, !rc); 5459 MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLEND, uirow); 5460 msiobj_release(&uirow->hdr); 5461 } 5462 else 5463 rc = ACTION_PerformAction(package, action); 5464 5465 /* Send all set properties. */ 5466 if (!MSI_OpenQuery(package->db, &view, L"SELECT * FROM `_Property`")) 5467 { 5468 MSI_IterateRecords(view, NULL, iterate_properties, package); 5469 msiobj_release(&view->hdr); 5470 } 5471 5472 /* And finally, toggle the cancel off and on. */ 5473 uirow = MSI_CreateRecord(2); 5474 if (!uirow) 5475 { 5476 rc = ERROR_OUTOFMEMORY; 5477 goto end; 5478 } 5479 MSI_RecordSetStringW(uirow, 0, NULL); 5480 MSI_RecordSetInteger(uirow, 1, 2); 5481 MSI_RecordSetInteger(uirow, 2, 0); 5482 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow); 5483 MSI_RecordSetInteger(uirow, 2, 1); 5484 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow); 5485 msiobj_release(&uirow->hdr); 5486 5487 end: 5488 free(productname); 5489 free(action); 5490 return rc; 5491 } 5492 5493 static UINT ACTION_INSTALL(MSIPACKAGE *package) 5494 { 5495 msi_set_property(package->db, L"EXECUTEACTION", L"INSTALL", -1); 5496 if (needs_ui_sequence(package) && ui_sequence_exists(package)) 5497 { 5498 package->InWhatSequence |= SEQUENCE_UI; 5499 return ACTION_ProcessUISequence(package); 5500 } 5501 else 5502 return ACTION_ExecuteAction(package); 5503 } 5504 5505 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature ) 5506 { 5507 WCHAR productid_85[21], component_85[21], *ret; 5508 GUID clsid; 5509 DWORD sz; 5510 5511 /* > is used if there is a component GUID and < if not. */ 5512 5513 productid_85[0] = 0; 5514 component_85[0] = 0; 5515 CLSIDFromString( package->ProductCode, &clsid ); 5516 5517 encode_base85_guid( &clsid, productid_85 ); 5518 if (component) 5519 { 5520 CLSIDFromString( component->ComponentId, &clsid ); 5521 encode_base85_guid( &clsid, component_85 ); 5522 } 5523 5524 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature), 5525 debugstr_w(component_85)); 5526 5527 sz = 20 + lstrlenW( feature ) + 20 + 3; 5528 ret = calloc( 1, sz * sizeof(WCHAR) ); 5529 if (ret) swprintf( ret, sz, L"%s%s%c%s", productid_85, feature, component ? '>' : '<', component_85 ); 5530 return ret; 5531 } 5532 5533 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) 5534 { 5535 MSIPACKAGE *package = param; 5536 LPCWSTR compgroupid, component, feature, qualifier, text; 5537 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q; 5538 HKEY hkey = NULL; 5539 UINT rc; 5540 MSICOMPONENT *comp; 5541 MSIFEATURE *feat; 5542 DWORD sz; 5543 MSIRECORD *uirow; 5544 int len; 5545 5546 feature = MSI_RecordGetString(rec, 5); 5547 feat = msi_get_loaded_feature(package, feature); 5548 if (!feat) 5549 return ERROR_SUCCESS; 5550 5551 feat->Action = msi_get_feature_action( package, feat ); 5552 if (feat->Action != INSTALLSTATE_LOCAL && 5553 feat->Action != INSTALLSTATE_SOURCE && 5554 feat->Action != INSTALLSTATE_ADVERTISED) 5555 { 5556 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature)); 5557 return ERROR_SUCCESS; 5558 } 5559 5560 component = MSI_RecordGetString(rec, 3); 5561 comp = msi_get_loaded_component(package, component); 5562 if (!comp) 5563 return ERROR_SUCCESS; 5564 5565 compgroupid = MSI_RecordGetString(rec,1); 5566 qualifier = MSI_RecordGetString(rec,2); 5567 5568 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); 5569 if (rc != ERROR_SUCCESS) 5570 goto end; 5571 5572 advertise = msi_create_component_advertise_string( package, comp, feature ); 5573 text = MSI_RecordGetString( rec, 4 ); 5574 if (text) 5575 { 5576 p = malloc( (wcslen( advertise ) + wcslen( text ) + 1) * sizeof(WCHAR) ); 5577 lstrcpyW( p, advertise ); 5578 lstrcatW( p, text ); 5579 free( advertise ); 5580 advertise = p; 5581 } 5582 existing = msi_reg_get_val_str( hkey, qualifier ); 5583 5584 sz = lstrlenW( advertise ) + 1; 5585 if (existing) 5586 { 5587 for (p = existing; *p; p += len) 5588 { 5589 len = lstrlenW( p ) + 1; 5590 if (wcscmp( advertise, p )) sz += len; 5591 } 5592 } 5593 if (!(output = malloc( (sz + 1) * sizeof(WCHAR) ))) 5594 { 5595 rc = ERROR_OUTOFMEMORY; 5596 goto end; 5597 } 5598 q = output; 5599 if (existing) 5600 { 5601 for (p = existing; *p; p += len) 5602 { 5603 len = lstrlenW( p ) + 1; 5604 if (wcscmp( advertise, p )) 5605 { 5606 memcpy( q, p, len * sizeof(WCHAR) ); 5607 q += len; 5608 } 5609 } 5610 } 5611 lstrcpyW( q, advertise ); 5612 q[lstrlenW( q ) + 1] = 0; 5613 5614 msi_reg_set_val_multi_str( hkey, qualifier, output ); 5615 5616 end: 5617 RegCloseKey(hkey); 5618 free( output ); 5619 free( advertise ); 5620 free( existing ); 5621 5622 /* the UI chunk */ 5623 uirow = MSI_CreateRecord( 2 ); 5624 MSI_RecordSetStringW( uirow, 1, compgroupid ); 5625 MSI_RecordSetStringW( uirow, 2, qualifier); 5626 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 5627 msiobj_release( &uirow->hdr ); 5628 /* FIXME: call ui_progress? */ 5629 5630 return rc; 5631 } 5632 5633 /* 5634 * At present I am ignoring the advertised components part of this and only 5635 * focusing on the qualified component sets 5636 */ 5637 static UINT ACTION_PublishComponents(MSIPACKAGE *package) 5638 { 5639 MSIQUERY *view; 5640 UINT rc; 5641 5642 if (package->script == SCRIPT_NONE) 5643 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishComponents"); 5644 5645 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `PublishComponent`", &view); 5646 if (rc != ERROR_SUCCESS) 5647 return ERROR_SUCCESS; 5648 5649 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package); 5650 msiobj_release(&view->hdr); 5651 return rc; 5652 } 5653 5654 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param ) 5655 { 5656 MSIPACKAGE *package = param; 5657 LPCWSTR compgroupid, component, feature, qualifier; 5658 MSICOMPONENT *comp; 5659 MSIFEATURE *feat; 5660 MSIRECORD *uirow; 5661 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH]; 5662 LONG res; 5663 5664 feature = MSI_RecordGetString( rec, 5 ); 5665 feat = msi_get_loaded_feature( package, feature ); 5666 if (!feat) 5667 return ERROR_SUCCESS; 5668 5669 feat->Action = msi_get_feature_action( package, feat ); 5670 if (feat->Action != INSTALLSTATE_ABSENT) 5671 { 5672 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature)); 5673 return ERROR_SUCCESS; 5674 } 5675 5676 component = MSI_RecordGetString( rec, 3 ); 5677 comp = msi_get_loaded_component( package, component ); 5678 if (!comp) 5679 return ERROR_SUCCESS; 5680 5681 compgroupid = MSI_RecordGetString( rec, 1 ); 5682 qualifier = MSI_RecordGetString( rec, 2 ); 5683 5684 squash_guid( compgroupid, squashed ); 5685 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Components\\" ); 5686 lstrcatW( keypath, squashed ); 5687 5688 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath ); 5689 if (res != ERROR_SUCCESS) 5690 { 5691 WARN( "unable to delete component key %ld\n", res ); 5692 } 5693 5694 uirow = MSI_CreateRecord( 2 ); 5695 MSI_RecordSetStringW( uirow, 1, compgroupid ); 5696 MSI_RecordSetStringW( uirow, 2, qualifier ); 5697 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 5698 msiobj_release( &uirow->hdr ); 5699 5700 return ERROR_SUCCESS; 5701 } 5702 5703 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) 5704 { 5705 MSIQUERY *view; 5706 UINT rc; 5707 5708 if (package->script == SCRIPT_NONE) 5709 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnpublishComponents"); 5710 5711 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `PublishComponent`", &view ); 5712 if (rc != ERROR_SUCCESS) 5713 return ERROR_SUCCESS; 5714 5715 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package ); 5716 msiobj_release( &view->hdr ); 5717 return rc; 5718 } 5719 5720 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param) 5721 { 5722 MSIPACKAGE *package = param; 5723 MSICOMPONENT *component; 5724 MSIRECORD *row; 5725 MSIFILE *file; 5726 SC_HANDLE hscm = NULL, service = NULL; 5727 LPCWSTR comp, key; 5728 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL; 5729 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL; 5730 DWORD serv_type, start_type, err_control; 5731 BOOL is_vital; 5732 SERVICE_DESCRIPTIONW sd = {NULL}; 5733 UINT ret = ERROR_SUCCESS; 5734 5735 comp = MSI_RecordGetString( rec, 12 ); 5736 component = msi_get_loaded_component( package, comp ); 5737 if (!component) 5738 { 5739 WARN("service component not found\n"); 5740 goto done; 5741 } 5742 component->Action = msi_get_component_action( package, component ); 5743 if (component->Action != INSTALLSTATE_LOCAL) 5744 { 5745 TRACE("component not scheduled for installation %s\n", debugstr_w(comp)); 5746 goto done; 5747 } 5748 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE); 5749 if (!hscm) 5750 { 5751 ERR("Failed to open the SC Manager!\n"); 5752 goto done; 5753 } 5754 5755 start_type = MSI_RecordGetInteger(rec, 5); 5756 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START) 5757 goto done; 5758 5759 deformat_string(package, MSI_RecordGetString(rec, 2), &name); 5760 deformat_string(package, MSI_RecordGetString(rec, 3), &disp); 5761 serv_type = MSI_RecordGetInteger(rec, 4); 5762 err_control = MSI_RecordGetInteger(rec, 6); 5763 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order); 5764 deformat_string(package, MSI_RecordGetString(rec, 8), &depends); 5765 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name); 5766 deformat_string(package, MSI_RecordGetString(rec, 10), &pass); 5767 deformat_string(package, MSI_RecordGetString(rec, 11), &args); 5768 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription); 5769 5770 /* Should the complete install fail if CreateService fails? */ 5771 is_vital = (err_control & msidbServiceInstallErrorControlVital); 5772 5773 /* Remove the msidbServiceInstallErrorControlVital-flag from err_control. 5774 CreateService (under Windows) would fail if not. */ 5775 err_control &= ~msidbServiceInstallErrorControlVital; 5776 5777 /* fetch the service path */ 5778 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Component` WHERE `Component` = '%s'", comp); 5779 if (!row) 5780 { 5781 ERR("Query failed\n"); 5782 goto done; 5783 } 5784 if (!(key = MSI_RecordGetString(row, 6))) 5785 { 5786 msiobj_release(&row->hdr); 5787 goto done; 5788 } 5789 file = msi_get_loaded_file(package, key); 5790 msiobj_release(&row->hdr); 5791 if (!file) 5792 { 5793 ERR("Failed to load the service file\n"); 5794 goto done; 5795 } 5796 5797 if (!args || !args[0]) image_path = file->TargetPath; 5798 else 5799 { 5800 int len = lstrlenW(file->TargetPath) + lstrlenW(args) + 2; 5801 if (!(image_path = malloc(len * sizeof(WCHAR)))) 5802 { 5803 ret = ERROR_OUTOFMEMORY; 5804 goto done; 5805 } 5806 5807 lstrcpyW(image_path, file->TargetPath); 5808 lstrcatW(image_path, L" "); 5809 lstrcatW(image_path, args); 5810 } 5811 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type, 5812 start_type, err_control, image_path, load_order, 5813 NULL, depends, serv_name, pass); 5814 5815 if (!service) 5816 { 5817 if (GetLastError() != ERROR_SERVICE_EXISTS) 5818 { 5819 WARN( "failed to create service %s (%lu)\n", debugstr_w(name), GetLastError() ); 5820 if (is_vital) 5821 ret = ERROR_INSTALL_FAILURE; 5822 5823 } 5824 } 5825 else if (sd.lpDescription) 5826 { 5827 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd)) 5828 WARN( "failed to set service description %lu\n", GetLastError() ); 5829 } 5830 5831 if (image_path != file->TargetPath) free(image_path); 5832 done: 5833 if (service) CloseServiceHandle(service); 5834 if (hscm) CloseServiceHandle(hscm); 5835 free(name); 5836 free(disp); 5837 free(sd.lpDescription); 5838 free(load_order); 5839 free(serv_name); 5840 free(pass); 5841 free(depends); 5842 free(args); 5843 5844 return ret; 5845 } 5846 5847 static UINT ACTION_InstallServices( MSIPACKAGE *package ) 5848 { 5849 MSIQUERY *view; 5850 UINT rc; 5851 5852 if (package->script == SCRIPT_NONE) 5853 return msi_schedule_action(package, SCRIPT_INSTALL, L"InstallServices"); 5854 5855 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceInstall`", &view); 5856 if (rc != ERROR_SUCCESS) 5857 return ERROR_SUCCESS; 5858 5859 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package); 5860 msiobj_release(&view->hdr); 5861 return rc; 5862 } 5863 5864 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */ 5865 static const WCHAR **service_args_to_vector(WCHAR *args, DWORD *numargs) 5866 { 5867 LPCWSTR *vector, *temp_vector; 5868 LPWSTR p, q; 5869 DWORD sep_len; 5870 5871 *numargs = 0; 5872 sep_len = ARRAY_SIZE(L"[~]") - 1; 5873 5874 if (!args) 5875 return NULL; 5876 5877 vector = malloc(sizeof(WCHAR *)); 5878 if (!vector) 5879 return NULL; 5880 5881 p = args; 5882 do 5883 { 5884 (*numargs)++; 5885 vector[*numargs - 1] = p; 5886 5887 if ((q = wcsstr(p, L"[~]"))) 5888 { 5889 *q = '\0'; 5890 5891 temp_vector = realloc(vector, (*numargs + 1) * sizeof(WCHAR *)); 5892 if (!temp_vector) 5893 { 5894 free(vector); 5895 return NULL; 5896 } 5897 vector = temp_vector; 5898 5899 p = q + sep_len; 5900 } 5901 } while (q); 5902 5903 return vector; 5904 } 5905 5906 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) 5907 { 5908 MSIPACKAGE *package = param; 5909 MSICOMPONENT *comp; 5910 MSIRECORD *uirow; 5911 SC_HANDLE scm = NULL, service = NULL; 5912 LPCWSTR component, *vector = NULL; 5913 LPWSTR name, args, display_name = NULL; 5914 DWORD event, numargs, len, wait, dummy; 5915 UINT r = ERROR_FUNCTION_FAILED; 5916 SERVICE_STATUS_PROCESS status; 5917 ULONGLONG start_time; 5918 5919 component = MSI_RecordGetString(rec, 6); 5920 comp = msi_get_loaded_component(package, component); 5921 if (!comp) 5922 return ERROR_SUCCESS; 5923 5924 event = MSI_RecordGetInteger( rec, 3 ); 5925 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); 5926 5927 comp->Action = msi_get_component_action( package, comp ); 5928 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStart)) && 5929 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStart))) 5930 { 5931 TRACE("not starting %s\n", debugstr_w(name)); 5932 free(name); 5933 return ERROR_SUCCESS; 5934 } 5935 5936 deformat_string(package, MSI_RecordGetString(rec, 4), &args); 5937 wait = MSI_RecordGetInteger(rec, 5); 5938 5939 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); 5940 if (!scm) 5941 { 5942 ERR("Failed to open the service control manager\n"); 5943 goto done; 5944 } 5945 5946 len = 0; 5947 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && 5948 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 5949 { 5950 if ((display_name = malloc(++len * sizeof(WCHAR)))) 5951 GetServiceDisplayNameW( scm, name, display_name, &len ); 5952 } 5953 5954 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS); 5955 if (!service) 5956 { 5957 ERR( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() ); 5958 goto done; 5959 } 5960 5961 vector = service_args_to_vector(args, &numargs); 5962 5963 if (!StartServiceW(service, numargs, vector) && 5964 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) 5965 { 5966 ERR( "failed to start service %s (%lu)\n", debugstr_w(name), GetLastError() ); 5967 goto done; 5968 } 5969 5970 r = ERROR_SUCCESS; 5971 if (wait) 5972 { 5973 /* wait for at most 30 seconds for the service to be up and running */ 5974 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, 5975 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy)) 5976 { 5977 TRACE( "failed to query service status (%lu)\n", GetLastError() ); 5978 goto done; 5979 } 5980 start_time = GetTickCount64(); 5981 while (status.dwCurrentState == SERVICE_START_PENDING) 5982 { 5983 if (GetTickCount64() - start_time > 30000) break; 5984 Sleep(1000); 5985 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, 5986 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy)) 5987 { 5988 TRACE( "failed to query service status (%lu)\n", GetLastError() ); 5989 goto done; 5990 } 5991 } 5992 if (status.dwCurrentState != SERVICE_RUNNING) 5993 { 5994 WARN( "service failed to start %lu\n", status.dwCurrentState ); 5995 r = ERROR_FUNCTION_FAILED; 5996 } 5997 } 5998 5999 done: 6000 uirow = MSI_CreateRecord( 2 ); 6001 MSI_RecordSetStringW( uirow, 1, display_name ); 6002 MSI_RecordSetStringW( uirow, 2, name ); 6003 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6004 msiobj_release( &uirow->hdr ); 6005 6006 if (service) CloseServiceHandle(service); 6007 if (scm) CloseServiceHandle(scm); 6008 6009 free(name); 6010 free(args); 6011 free(vector); 6012 free(display_name); 6013 return r; 6014 } 6015 6016 static UINT ACTION_StartServices( MSIPACKAGE *package ) 6017 { 6018 MSIQUERY *view; 6019 UINT rc; 6020 6021 if (package->script == SCRIPT_NONE) 6022 return msi_schedule_action(package, SCRIPT_INSTALL, L"StartServices"); 6023 6024 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceControl`", &view); 6025 if (rc != ERROR_SUCCESS) 6026 return ERROR_SUCCESS; 6027 6028 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package); 6029 msiobj_release(&view->hdr); 6030 return rc; 6031 } 6032 6033 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service) 6034 { 6035 DWORD i, needed, count; 6036 ENUM_SERVICE_STATUSW *dependencies; 6037 SERVICE_STATUS ss; 6038 SC_HANDLE depserv; 6039 BOOL stopped, ret = FALSE; 6040 6041 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL, 6042 0, &needed, &count)) 6043 return TRUE; 6044 6045 if (GetLastError() != ERROR_MORE_DATA) 6046 return FALSE; 6047 6048 dependencies = malloc(needed); 6049 if (!dependencies) 6050 return FALSE; 6051 6052 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies, 6053 needed, &needed, &count)) 6054 goto done; 6055 6056 for (i = 0; i < count; i++) 6057 { 6058 depserv = OpenServiceW(scm, dependencies[i].lpServiceName, 6059 SERVICE_STOP | SERVICE_QUERY_STATUS); 6060 if (!depserv) 6061 goto done; 6062 6063 stopped = ControlService(depserv, SERVICE_CONTROL_STOP, &ss); 6064 CloseServiceHandle(depserv); 6065 if (!stopped) 6066 goto done; 6067 } 6068 6069 ret = TRUE; 6070 6071 done: 6072 free(dependencies); 6073 return ret; 6074 } 6075 6076 static UINT stop_service( LPCWSTR name ) 6077 { 6078 SC_HANDLE scm = NULL, service = NULL; 6079 SERVICE_STATUS status; 6080 SERVICE_STATUS_PROCESS ssp; 6081 DWORD needed; 6082 6083 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); 6084 if (!scm) 6085 { 6086 WARN( "failed to open the SCM (%lu)\n", GetLastError() ); 6087 goto done; 6088 } 6089 6090 service = OpenServiceW(scm, name, SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS); 6091 if (!service) 6092 { 6093 WARN( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() ); 6094 goto done; 6095 } 6096 6097 if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&ssp, sizeof(ssp), &needed) ) 6098 { 6099 WARN( "failed to query service status %s (%lu)\n", debugstr_w(name), GetLastError() ); 6100 goto done; 6101 } 6102 6103 if (ssp.dwCurrentState == SERVICE_STOPPED) 6104 goto done; 6105 6106 stop_service_dependents(scm, service); 6107 6108 if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) 6109 WARN( "failed to stop service %s (%lu)\n", debugstr_w(name), GetLastError() ); 6110 6111 done: 6112 if (service) CloseServiceHandle(service); 6113 if (scm) CloseServiceHandle(scm); 6114 6115 return ERROR_SUCCESS; 6116 } 6117 6118 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param ) 6119 { 6120 MSIPACKAGE *package = param; 6121 MSICOMPONENT *comp; 6122 MSIRECORD *uirow; 6123 LPCWSTR component; 6124 WCHAR *name, *display_name = NULL; 6125 DWORD event, len; 6126 SC_HANDLE scm; 6127 6128 component = MSI_RecordGetString( rec, 6 ); 6129 comp = msi_get_loaded_component( package, component ); 6130 if (!comp) 6131 return ERROR_SUCCESS; 6132 6133 event = MSI_RecordGetInteger( rec, 3 ); 6134 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); 6135 6136 comp->Action = msi_get_component_action( package, comp ); 6137 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStop)) && 6138 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStop))) 6139 { 6140 TRACE("not stopping %s\n", debugstr_w(name)); 6141 free( name ); 6142 return ERROR_SUCCESS; 6143 } 6144 6145 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); 6146 if (!scm) 6147 { 6148 ERR("Failed to open the service control manager\n"); 6149 goto done; 6150 } 6151 6152 len = 0; 6153 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && 6154 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 6155 { 6156 if ((display_name = malloc( ++len * sizeof(WCHAR )))) 6157 GetServiceDisplayNameW( scm, name, display_name, &len ); 6158 } 6159 CloseServiceHandle( scm ); 6160 6161 stop_service( name ); 6162 6163 done: 6164 uirow = MSI_CreateRecord( 2 ); 6165 MSI_RecordSetStringW( uirow, 1, display_name ); 6166 MSI_RecordSetStringW( uirow, 2, name ); 6167 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6168 msiobj_release( &uirow->hdr ); 6169 6170 free( name ); 6171 free( display_name ); 6172 return ERROR_SUCCESS; 6173 } 6174 6175 static UINT ACTION_StopServices( MSIPACKAGE *package ) 6176 { 6177 MSIQUERY *view; 6178 UINT rc; 6179 6180 if (package->script == SCRIPT_NONE) 6181 return msi_schedule_action(package, SCRIPT_INSTALL, L"StopServices"); 6182 6183 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceControl`", &view); 6184 if (rc != ERROR_SUCCESS) 6185 return ERROR_SUCCESS; 6186 6187 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package); 6188 msiobj_release(&view->hdr); 6189 return rc; 6190 } 6191 6192 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param ) 6193 { 6194 MSIPACKAGE *package = param; 6195 MSICOMPONENT *comp; 6196 MSIRECORD *uirow; 6197 LPWSTR name = NULL, display_name = NULL; 6198 DWORD event, len; 6199 SC_HANDLE scm = NULL, service = NULL; 6200 6201 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) ); 6202 if (!comp) 6203 return ERROR_SUCCESS; 6204 6205 event = MSI_RecordGetInteger( rec, 3 ); 6206 deformat_string( package, MSI_RecordGetString(rec, 2), &name ); 6207 6208 comp->Action = msi_get_component_action( package, comp ); 6209 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) && 6210 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete))) 6211 { 6212 TRACE("service %s not scheduled for removal\n", debugstr_w(name)); 6213 free( name ); 6214 return ERROR_SUCCESS; 6215 } 6216 stop_service( name ); 6217 6218 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS ); 6219 if (!scm) 6220 { 6221 WARN( "failed to open the SCM (%lu)\n", GetLastError() ); 6222 goto done; 6223 } 6224 6225 len = 0; 6226 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && 6227 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 6228 { 6229 if ((display_name = malloc( ++len * sizeof(WCHAR )))) 6230 GetServiceDisplayNameW( scm, name, display_name, &len ); 6231 } 6232 6233 service = OpenServiceW( scm, name, DELETE ); 6234 if (!service) 6235 { 6236 WARN( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() ); 6237 goto done; 6238 } 6239 6240 if (!DeleteService( service )) 6241 WARN( "failed to delete service %s (%lu)\n", debugstr_w(name), GetLastError() ); 6242 6243 done: 6244 uirow = MSI_CreateRecord( 2 ); 6245 MSI_RecordSetStringW( uirow, 1, display_name ); 6246 MSI_RecordSetStringW( uirow, 2, name ); 6247 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6248 msiobj_release( &uirow->hdr ); 6249 6250 if (service) CloseServiceHandle( service ); 6251 if (scm) CloseServiceHandle( scm ); 6252 free( name ); 6253 free( display_name ); 6254 6255 return ERROR_SUCCESS; 6256 } 6257 6258 static UINT ACTION_DeleteServices( MSIPACKAGE *package ) 6259 { 6260 MSIQUERY *view; 6261 UINT rc; 6262 6263 if (package->script == SCRIPT_NONE) 6264 return msi_schedule_action(package, SCRIPT_INSTALL, L"DeleteServices"); 6265 6266 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ServiceControl`", &view ); 6267 if (rc != ERROR_SUCCESS) 6268 return ERROR_SUCCESS; 6269 6270 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package ); 6271 msiobj_release( &view->hdr ); 6272 return rc; 6273 } 6274 6275 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param ) 6276 { 6277 MSIPACKAGE *package = param; 6278 LPWSTR driver, driver_path, ptr; 6279 WCHAR outpath[MAX_PATH]; 6280 MSIFILE *driver_file = NULL, *setup_file = NULL; 6281 MSICOMPONENT *comp; 6282 MSIRECORD *uirow; 6283 LPCWSTR desc, file_key, component; 6284 DWORD len, usage; 6285 UINT r = ERROR_SUCCESS; 6286 6287 component = MSI_RecordGetString( rec, 2 ); 6288 comp = msi_get_loaded_component( package, component ); 6289 if (!comp) 6290 return ERROR_SUCCESS; 6291 6292 comp->Action = msi_get_component_action( package, comp ); 6293 if (comp->Action != INSTALLSTATE_LOCAL) 6294 { 6295 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 6296 return ERROR_SUCCESS; 6297 } 6298 desc = MSI_RecordGetString(rec, 3); 6299 6300 file_key = MSI_RecordGetString( rec, 4 ); 6301 if (file_key) driver_file = msi_get_loaded_file( package, file_key ); 6302 6303 file_key = MSI_RecordGetString( rec, 5 ); 6304 if (file_key) setup_file = msi_get_loaded_file( package, file_key ); 6305 6306 if (!driver_file) 6307 { 6308 ERR("ODBC Driver entry not found!\n"); 6309 return ERROR_FUNCTION_FAILED; 6310 } 6311 6312 len = lstrlenW(desc) + lstrlenW(L"Driver=%s") + lstrlenW(driver_file->FileName); 6313 if (setup_file) 6314 len += lstrlenW(L"Setup=%s") + lstrlenW(setup_file->FileName); 6315 len += lstrlenW(L"FileUsage=1") + 2; /* \0\0 */ 6316 6317 driver = malloc(len * sizeof(WCHAR)); 6318 if (!driver) 6319 return ERROR_OUTOFMEMORY; 6320 6321 ptr = driver; 6322 lstrcpyW(ptr, desc); 6323 ptr += lstrlenW(ptr) + 1; 6324 6325 len = swprintf(ptr, len - (ptr - driver), L"Driver=%s", driver_file->FileName); 6326 ptr += len + 1; 6327 6328 if (setup_file) 6329 { 6330 len = swprintf(ptr, len - (ptr - driver), L"Setup=%s", setup_file->FileName); 6331 ptr += len + 1; 6332 } 6333 6334 lstrcpyW(ptr, L"FileUsage=1"); 6335 ptr += lstrlenW(ptr) + 1; 6336 *ptr = '\0'; 6337 6338 if (!driver_file->TargetPath) 6339 { 6340 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory ); 6341 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName ); 6342 } 6343 driver_path = wcsdup(driver_file->TargetPath); 6344 ptr = wcsrchr(driver_path, '\\'); 6345 if (ptr) *ptr = '\0'; 6346 6347 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH, 6348 NULL, ODBC_INSTALL_COMPLETE, &usage)) 6349 { 6350 ERR("Failed to install SQL driver!\n"); 6351 r = ERROR_FUNCTION_FAILED; 6352 } 6353 6354 uirow = MSI_CreateRecord( 5 ); 6355 MSI_RecordSetStringW( uirow, 1, desc ); 6356 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 6357 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory ); 6358 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6359 msiobj_release( &uirow->hdr ); 6360 6361 free(driver); 6362 free(driver_path); 6363 6364 return r; 6365 } 6366 6367 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param ) 6368 { 6369 MSIPACKAGE *package = param; 6370 LPWSTR translator, translator_path, ptr; 6371 WCHAR outpath[MAX_PATH]; 6372 MSIFILE *translator_file = NULL, *setup_file = NULL; 6373 MSICOMPONENT *comp; 6374 MSIRECORD *uirow; 6375 LPCWSTR desc, file_key, component; 6376 DWORD len, usage; 6377 UINT r = ERROR_SUCCESS; 6378 6379 component = MSI_RecordGetString( rec, 2 ); 6380 comp = msi_get_loaded_component( package, component ); 6381 if (!comp) 6382 return ERROR_SUCCESS; 6383 6384 comp->Action = msi_get_component_action( package, comp ); 6385 if (comp->Action != INSTALLSTATE_LOCAL) 6386 { 6387 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 6388 return ERROR_SUCCESS; 6389 } 6390 desc = MSI_RecordGetString(rec, 3); 6391 6392 file_key = MSI_RecordGetString( rec, 4 ); 6393 if (file_key) translator_file = msi_get_loaded_file( package, file_key ); 6394 6395 file_key = MSI_RecordGetString( rec, 5 ); 6396 if (file_key) setup_file = msi_get_loaded_file( package, file_key ); 6397 6398 if (!translator_file) 6399 { 6400 ERR("ODBC Translator entry not found!\n"); 6401 return ERROR_FUNCTION_FAILED; 6402 } 6403 6404 len = lstrlenW(desc) + lstrlenW(L"Translator=%s") + lstrlenW(translator_file->FileName) + 2; /* \0\0 */ 6405 if (setup_file) 6406 len += lstrlenW(L"Setup=%s") + lstrlenW(setup_file->FileName); 6407 6408 translator = malloc(len * sizeof(WCHAR)); 6409 if (!translator) 6410 return ERROR_OUTOFMEMORY; 6411 6412 ptr = translator; 6413 lstrcpyW(ptr, desc); 6414 ptr += lstrlenW(ptr) + 1; 6415 6416 len = swprintf(ptr, len - (ptr - translator), L"Translator=%s", translator_file->FileName); 6417 ptr += len + 1; 6418 6419 if (setup_file) 6420 { 6421 len = swprintf(ptr, len - (ptr - translator), L"Setup=%s", setup_file->FileName); 6422 ptr += len + 1; 6423 } 6424 *ptr = '\0'; 6425 6426 translator_path = wcsdup(translator_file->TargetPath); 6427 ptr = wcsrchr(translator_path, '\\'); 6428 if (ptr) *ptr = '\0'; 6429 6430 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH, 6431 NULL, ODBC_INSTALL_COMPLETE, &usage)) 6432 { 6433 ERR("Failed to install SQL translator!\n"); 6434 r = ERROR_FUNCTION_FAILED; 6435 } 6436 6437 uirow = MSI_CreateRecord( 5 ); 6438 MSI_RecordSetStringW( uirow, 1, desc ); 6439 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 6440 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory ); 6441 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6442 msiobj_release( &uirow->hdr ); 6443 6444 free(translator); 6445 free(translator_path); 6446 6447 return r; 6448 } 6449 6450 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param ) 6451 { 6452 MSIPACKAGE *package = param; 6453 MSICOMPONENT *comp; 6454 LPWSTR attrs; 6455 LPCWSTR desc, driver, component; 6456 WORD request = ODBC_ADD_SYS_DSN; 6457 INT registration; 6458 DWORD len; 6459 UINT r = ERROR_SUCCESS; 6460 MSIRECORD *uirow; 6461 6462 component = MSI_RecordGetString( rec, 2 ); 6463 comp = msi_get_loaded_component( package, component ); 6464 if (!comp) 6465 return ERROR_SUCCESS; 6466 6467 comp->Action = msi_get_component_action( package, comp ); 6468 if (comp->Action != INSTALLSTATE_LOCAL) 6469 { 6470 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 6471 return ERROR_SUCCESS; 6472 } 6473 6474 desc = MSI_RecordGetString(rec, 3); 6475 driver = MSI_RecordGetString(rec, 4); 6476 registration = MSI_RecordGetInteger(rec, 5); 6477 6478 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN; 6479 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN; 6480 6481 len = lstrlenW(L"DSN=%s") + lstrlenW(desc) + 2; /* \0\0 */ 6482 attrs = malloc(len * sizeof(WCHAR)); 6483 if (!attrs) 6484 return ERROR_OUTOFMEMORY; 6485 6486 len = swprintf(attrs, len, L"DSN=%s", desc); 6487 attrs[len + 1] = 0; 6488 6489 if (!SQLConfigDataSourceW(NULL, request, driver, attrs)) 6490 WARN("Failed to install SQL data source!\n"); 6491 6492 uirow = MSI_CreateRecord( 5 ); 6493 MSI_RecordSetStringW( uirow, 1, desc ); 6494 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 6495 MSI_RecordSetInteger( uirow, 3, request ); 6496 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6497 msiobj_release( &uirow->hdr ); 6498 6499 free(attrs); 6500 6501 return r; 6502 } 6503 6504 static UINT ACTION_InstallODBC( MSIPACKAGE *package ) 6505 { 6506 MSIQUERY *view; 6507 UINT rc; 6508 6509 if (package->script == SCRIPT_NONE) 6510 return msi_schedule_action(package, SCRIPT_INSTALL, L"InstallODBC"); 6511 6512 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCDriver`", &view); 6513 if (rc == ERROR_SUCCESS) 6514 { 6515 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package); 6516 msiobj_release(&view->hdr); 6517 if (rc != ERROR_SUCCESS) 6518 return rc; 6519 } 6520 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCTranslator`", &view); 6521 if (rc == ERROR_SUCCESS) 6522 { 6523 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package); 6524 msiobj_release(&view->hdr); 6525 if (rc != ERROR_SUCCESS) 6526 return rc; 6527 } 6528 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCDataSource`", &view); 6529 if (rc == ERROR_SUCCESS) 6530 { 6531 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package); 6532 msiobj_release(&view->hdr); 6533 if (rc != ERROR_SUCCESS) 6534 return rc; 6535 } 6536 return ERROR_SUCCESS; 6537 } 6538 6539 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param ) 6540 { 6541 MSIPACKAGE *package = param; 6542 MSICOMPONENT *comp; 6543 MSIRECORD *uirow; 6544 DWORD usage; 6545 LPCWSTR desc, component; 6546 6547 component = MSI_RecordGetString( rec, 2 ); 6548 comp = msi_get_loaded_component( package, component ); 6549 if (!comp) 6550 return ERROR_SUCCESS; 6551 6552 comp->Action = msi_get_component_action( package, comp ); 6553 if (comp->Action != INSTALLSTATE_ABSENT) 6554 { 6555 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 6556 return ERROR_SUCCESS; 6557 } 6558 6559 desc = MSI_RecordGetString( rec, 3 ); 6560 if (!SQLRemoveDriverW( desc, FALSE, &usage )) 6561 { 6562 WARN("Failed to remove ODBC driver\n"); 6563 } 6564 else if (!usage) 6565 { 6566 FIXME("Usage count reached 0\n"); 6567 } 6568 6569 uirow = MSI_CreateRecord( 2 ); 6570 MSI_RecordSetStringW( uirow, 1, desc ); 6571 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 6572 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6573 msiobj_release( &uirow->hdr ); 6574 6575 return ERROR_SUCCESS; 6576 } 6577 6578 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param ) 6579 { 6580 MSIPACKAGE *package = param; 6581 MSICOMPONENT *comp; 6582 MSIRECORD *uirow; 6583 DWORD usage; 6584 LPCWSTR desc, component; 6585 6586 component = MSI_RecordGetString( rec, 2 ); 6587 comp = msi_get_loaded_component( package, component ); 6588 if (!comp) 6589 return ERROR_SUCCESS; 6590 6591 comp->Action = msi_get_component_action( package, comp ); 6592 if (comp->Action != INSTALLSTATE_ABSENT) 6593 { 6594 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 6595 return ERROR_SUCCESS; 6596 } 6597 6598 desc = MSI_RecordGetString( rec, 3 ); 6599 if (!SQLRemoveTranslatorW( desc, &usage )) 6600 { 6601 WARN("Failed to remove ODBC translator\n"); 6602 } 6603 else if (!usage) 6604 { 6605 FIXME("Usage count reached 0\n"); 6606 } 6607 6608 uirow = MSI_CreateRecord( 2 ); 6609 MSI_RecordSetStringW( uirow, 1, desc ); 6610 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 6611 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6612 msiobj_release( &uirow->hdr ); 6613 6614 return ERROR_SUCCESS; 6615 } 6616 6617 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param ) 6618 { 6619 MSIPACKAGE *package = param; 6620 MSICOMPONENT *comp; 6621 MSIRECORD *uirow; 6622 LPWSTR attrs; 6623 LPCWSTR desc, driver, component; 6624 WORD request = ODBC_REMOVE_SYS_DSN; 6625 INT registration; 6626 DWORD len; 6627 6628 component = MSI_RecordGetString( rec, 2 ); 6629 comp = msi_get_loaded_component( package, component ); 6630 if (!comp) 6631 return ERROR_SUCCESS; 6632 6633 comp->Action = msi_get_component_action( package, comp ); 6634 if (comp->Action != INSTALLSTATE_ABSENT) 6635 { 6636 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 6637 return ERROR_SUCCESS; 6638 } 6639 6640 desc = MSI_RecordGetString( rec, 3 ); 6641 driver = MSI_RecordGetString( rec, 4 ); 6642 registration = MSI_RecordGetInteger( rec, 5 ); 6643 6644 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN; 6645 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN; 6646 6647 len = lstrlenW( L"DSN=%s" ) + lstrlenW( desc ) + 2; /* \0\0 */ 6648 attrs = malloc( len * sizeof(WCHAR) ); 6649 if (!attrs) 6650 return ERROR_OUTOFMEMORY; 6651 6652 FIXME("Use ODBCSourceAttribute table\n"); 6653 6654 len = swprintf( attrs, len, L"DSN=%s", desc ); 6655 attrs[len + 1] = 0; 6656 6657 if (!SQLConfigDataSourceW( NULL, request, driver, attrs )) 6658 { 6659 WARN("Failed to remove ODBC data source\n"); 6660 } 6661 free( attrs ); 6662 6663 uirow = MSI_CreateRecord( 3 ); 6664 MSI_RecordSetStringW( uirow, 1, desc ); 6665 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 6666 MSI_RecordSetInteger( uirow, 3, request ); 6667 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 6668 msiobj_release( &uirow->hdr ); 6669 6670 return ERROR_SUCCESS; 6671 } 6672 6673 static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) 6674 { 6675 MSIQUERY *view; 6676 UINT rc; 6677 6678 if (package->script == SCRIPT_NONE) 6679 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveODBC"); 6680 6681 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDriver`", &view ); 6682 if (rc == ERROR_SUCCESS) 6683 { 6684 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package ); 6685 msiobj_release( &view->hdr ); 6686 if (rc != ERROR_SUCCESS) 6687 return rc; 6688 } 6689 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCTranslator`", &view ); 6690 if (rc == ERROR_SUCCESS) 6691 { 6692 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package ); 6693 msiobj_release( &view->hdr ); 6694 if (rc != ERROR_SUCCESS) 6695 return rc; 6696 } 6697 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDataSource`", &view ); 6698 if (rc == ERROR_SUCCESS) 6699 { 6700 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package ); 6701 msiobj_release( &view->hdr ); 6702 if (rc != ERROR_SUCCESS) 6703 return rc; 6704 } 6705 return ERROR_SUCCESS; 6706 } 6707 6708 #define ENV_ACT_SETALWAYS 0x1 6709 #define ENV_ACT_SETABSENT 0x2 6710 #define ENV_ACT_REMOVE 0x4 6711 #define ENV_ACT_REMOVEMATCH 0x8 6712 6713 #define ENV_MOD_MACHINE 0x20000000 6714 #define ENV_MOD_APPEND 0x40000000 6715 #define ENV_MOD_PREFIX 0x80000000 6716 #define ENV_MOD_MASK 0xC0000000 6717 6718 #define check_flag_combo(x, y) ((x) & ~(y)) == (y) 6719 6720 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) 6721 { 6722 const WCHAR *cptr = *name; 6723 6724 *flags = 0; 6725 while (*cptr) 6726 { 6727 if (*cptr == '=') 6728 *flags |= ENV_ACT_SETALWAYS; 6729 else if (*cptr == '+') 6730 *flags |= ENV_ACT_SETABSENT; 6731 else if (*cptr == '-') 6732 *flags |= ENV_ACT_REMOVE; 6733 else if (*cptr == '!') 6734 *flags |= ENV_ACT_REMOVEMATCH; 6735 else if (*cptr == '*') 6736 *flags |= ENV_MOD_MACHINE | ENV_ACT_REMOVE; 6737 else 6738 break; 6739 6740 cptr++; 6741 (*name)++; 6742 } 6743 6744 if (!*cptr) 6745 { 6746 ERR("Missing environment variable\n"); 6747 return ERROR_FUNCTION_FAILED; 6748 } 6749 6750 if (*value) 6751 { 6752 LPCWSTR ptr = *value; 6753 if (!wcsncmp(ptr, L"[~]", 3)) 6754 { 6755 if (ptr[3] == ';') 6756 { 6757 *flags |= ENV_MOD_APPEND; 6758 *value += 3; 6759 } 6760 else 6761 { 6762 *value = NULL; 6763 } 6764 } 6765 else if (lstrlenW(*value) >= 3) 6766 { 6767 ptr += lstrlenW(ptr) - 3; 6768 if (!wcscmp( ptr, L"[~]" )) 6769 { 6770 if ((ptr-1) > *value && *(ptr-1) == ';') 6771 { 6772 *flags |= ENV_MOD_PREFIX; 6773 /* the "[~]" will be removed by deformat_string */; 6774 } 6775 else 6776 { 6777 *value = NULL; 6778 } 6779 } 6780 } 6781 } 6782 6783 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) || 6784 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) || 6785 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) || 6786 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK)) 6787 { 6788 ERR( "invalid flags: %#lx\n", *flags ); 6789 return ERROR_FUNCTION_FAILED; 6790 } 6791 6792 if (!*flags) 6793 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE; 6794 6795 return ERROR_SUCCESS; 6796 } 6797 6798 static UINT open_env_key( DWORD flags, HKEY *key ) 6799 { 6800 const WCHAR *env; 6801 HKEY root; 6802 LONG res; 6803 6804 if (flags & ENV_MOD_MACHINE) 6805 { 6806 env = L"System\\CurrentControlSet\\Control\\Session Manager\\Environment"; 6807 root = HKEY_LOCAL_MACHINE; 6808 } 6809 else 6810 { 6811 env = L"Environment"; 6812 root = HKEY_CURRENT_USER; 6813 } 6814 6815 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key ); 6816 if (res != ERROR_SUCCESS) 6817 { 6818 WARN( "failed to open key %s (%ld)\n", debugstr_w(env), res ); 6819 return ERROR_FUNCTION_FAILED; 6820 } 6821 6822 return ERROR_SUCCESS; 6823 } 6824 6825 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) 6826 { 6827 MSIPACKAGE *package = param; 6828 LPCWSTR name, value, component; 6829 WCHAR *data = NULL, *newval = NULL, *deformatted = NULL, *p, *q; 6830 DWORD flags, type, size, len, len_value = 0; 6831 UINT res; 6832 HKEY env = NULL; 6833 MSICOMPONENT *comp; 6834 MSIRECORD *uirow; 6835 int action = 0, found = 0; 6836 6837 component = MSI_RecordGetString(rec, 4); 6838 comp = msi_get_loaded_component(package, component); 6839 if (!comp) 6840 return ERROR_SUCCESS; 6841 6842 comp->Action = msi_get_component_action( package, comp ); 6843 if (comp->Action != INSTALLSTATE_LOCAL) 6844 { 6845 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 6846 return ERROR_SUCCESS; 6847 } 6848 name = MSI_RecordGetString(rec, 2); 6849 value = MSI_RecordGetString(rec, 3); 6850 6851 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); 6852 6853 res = env_parse_flags(&name, &value, &flags); 6854 if (res != ERROR_SUCCESS || !value) 6855 goto done; 6856 6857 if (value) 6858 { 6859 DWORD len = deformat_string( package, value, &deformatted ); 6860 if (!deformatted) 6861 { 6862 res = ERROR_OUTOFMEMORY; 6863 goto done; 6864 } 6865 6866 if (len) 6867 { 6868 value = deformatted; 6869 if (flags & ENV_MOD_PREFIX) 6870 { 6871 p = wcsrchr( value, ';' ); 6872 len_value = p - value; 6873 } 6874 else if (flags & ENV_MOD_APPEND) 6875 { 6876 value = wcschr( value, ';' ) + 1; 6877 len_value = lstrlenW( value ); 6878 } 6879 else len_value = lstrlenW( value ); 6880 } 6881 else 6882 { 6883 value = NULL; 6884 } 6885 } 6886 6887 res = open_env_key( flags, &env ); 6888 if (res != ERROR_SUCCESS) 6889 goto done; 6890 6891 if (flags & ENV_MOD_MACHINE) 6892 action |= 0x20000000; 6893 6894 size = 0; 6895 type = REG_SZ; 6896 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size); 6897 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) || 6898 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)) 6899 goto done; 6900 6901 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK))) 6902 { 6903 action = 0x2; 6904 6905 /* Nothing to do. */ 6906 if (!value) 6907 { 6908 res = ERROR_SUCCESS; 6909 goto done; 6910 } 6911 size = (lstrlenW(value) + 1) * sizeof(WCHAR); 6912 newval = wcsdup(value); 6913 if (!newval) 6914 { 6915 res = ERROR_OUTOFMEMORY; 6916 goto done; 6917 } 6918 } 6919 else 6920 { 6921 action = 0x1; 6922 6923 /* Contrary to MSDN, +-variable to [~];path works */ 6924 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK)) 6925 { 6926 res = ERROR_SUCCESS; 6927 goto done; 6928 } 6929 6930 if (!(p = q = data = malloc( size ))) 6931 { 6932 free(deformatted); 6933 RegCloseKey(env); 6934 return ERROR_OUTOFMEMORY; 6935 } 6936 6937 res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)data, &size ); 6938 if (res != ERROR_SUCCESS) 6939 goto done; 6940 6941 if (flags & ENV_ACT_REMOVEMATCH && (!value || !wcscmp( data, value ))) 6942 { 6943 action = 0x4; 6944 res = RegDeleteValueW(env, name); 6945 if (res != ERROR_SUCCESS) 6946 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res); 6947 goto done; 6948 } 6949 6950 for (;;) 6951 { 6952 while (*q && *q != ';') q++; 6953 len = q - p; 6954 if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ) && 6955 (!p[len] || p[len] == ';')) 6956 { 6957 found = 1; 6958 break; 6959 } 6960 if (!*q) break; 6961 p = ++q; 6962 } 6963 6964 if (found) 6965 { 6966 TRACE("string already set\n"); 6967 goto done; 6968 } 6969 6970 size = (len_value + 1 + lstrlenW( data ) + 1) * sizeof(WCHAR); 6971 if (!(p = newval = malloc( size ))) 6972 { 6973 res = ERROR_OUTOFMEMORY; 6974 goto done; 6975 } 6976 6977 if (flags & ENV_MOD_PREFIX) 6978 { 6979 memcpy( newval, value, len_value * sizeof(WCHAR) ); 6980 newval[len_value] = ';'; 6981 p = newval + len_value + 1; 6982 action |= 0x80000000; 6983 } 6984 6985 lstrcpyW( p, data ); 6986 6987 if (flags & ENV_MOD_APPEND) 6988 { 6989 p += lstrlenW( data ); 6990 *p++ = ';'; 6991 memcpy( p, value, (len_value + 1) * sizeof(WCHAR) ); 6992 action |= 0x40000000; 6993 } 6994 } 6995 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval)); 6996 res = RegSetValueExW( env, name, 0, type, (BYTE *)newval, size ); 6997 if (res) 6998 { 6999 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res); 7000 } 7001 7002 done: 7003 uirow = MSI_CreateRecord( 3 ); 7004 MSI_RecordSetStringW( uirow, 1, name ); 7005 MSI_RecordSetStringW( uirow, 2, newval ); 7006 MSI_RecordSetInteger( uirow, 3, action ); 7007 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 7008 msiobj_release( &uirow->hdr ); 7009 7010 if (env) RegCloseKey(env); 7011 free(deformatted); 7012 free(data); 7013 free(newval); 7014 return res; 7015 } 7016 7017 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package ) 7018 { 7019 MSIQUERY *view; 7020 UINT rc; 7021 7022 if (package->script == SCRIPT_NONE) 7023 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteEnvironmentStrings"); 7024 7025 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Environment`", &view); 7026 if (rc != ERROR_SUCCESS) 7027 return ERROR_SUCCESS; 7028 7029 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package); 7030 msiobj_release(&view->hdr); 7031 return rc; 7032 } 7033 7034 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param ) 7035 { 7036 MSIPACKAGE *package = param; 7037 LPCWSTR name, value, component; 7038 WCHAR *p, *q, *deformatted = NULL, *new_value = NULL; 7039 DWORD flags, type, size, len, len_value = 0, len_new_value; 7040 HKEY env = NULL; 7041 MSICOMPONENT *comp; 7042 MSIRECORD *uirow; 7043 int action = 0; 7044 LONG res; 7045 UINT r; 7046 7047 component = MSI_RecordGetString( rec, 4 ); 7048 comp = msi_get_loaded_component( package, component ); 7049 if (!comp) 7050 return ERROR_SUCCESS; 7051 7052 comp->Action = msi_get_component_action( package, comp ); 7053 if (comp->Action != INSTALLSTATE_ABSENT) 7054 { 7055 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 7056 return ERROR_SUCCESS; 7057 } 7058 name = MSI_RecordGetString( rec, 2 ); 7059 value = MSI_RecordGetString( rec, 3 ); 7060 7061 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); 7062 7063 r = env_parse_flags( &name, &value, &flags ); 7064 if (r != ERROR_SUCCESS) 7065 return r; 7066 7067 if (!(flags & ENV_ACT_REMOVE)) 7068 { 7069 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name)); 7070 return ERROR_SUCCESS; 7071 } 7072 7073 if (value) 7074 { 7075 DWORD len = deformat_string( package, value, &deformatted ); 7076 if (!deformatted) 7077 { 7078 res = ERROR_OUTOFMEMORY; 7079 goto done; 7080 } 7081 7082 if (len) 7083 { 7084 value = deformatted; 7085 if (flags & ENV_MOD_PREFIX) 7086 { 7087 p = wcsrchr( value, ';' ); 7088 len_value = p - value; 7089 } 7090 else if (flags & ENV_MOD_APPEND) 7091 { 7092 value = wcschr( value, ';' ) + 1; 7093 len_value = lstrlenW( value ); 7094 } 7095 else len_value = lstrlenW( value ); 7096 } 7097 else 7098 { 7099 value = NULL; 7100 } 7101 } 7102 7103 r = open_env_key( flags, &env ); 7104 if (r != ERROR_SUCCESS) 7105 { 7106 r = ERROR_SUCCESS; 7107 goto done; 7108 } 7109 7110 if (flags & ENV_MOD_MACHINE) 7111 action |= 0x20000000; 7112 7113 size = 0; 7114 type = REG_SZ; 7115 res = RegQueryValueExW( env, name, NULL, &type, NULL, &size ); 7116 if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) 7117 goto done; 7118 7119 if (!(new_value = malloc( size ))) goto done; 7120 7121 res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)new_value, &size ); 7122 if (res != ERROR_SUCCESS) 7123 goto done; 7124 7125 len_new_value = size / sizeof(WCHAR) - 1; 7126 p = q = new_value; 7127 for (;;) 7128 { 7129 while (*q && *q != ';') q++; 7130 len = q - p; 7131 if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) )) 7132 { 7133 if (*q == ';') q++; 7134 memmove( p, q, (len_new_value - (q - new_value) + 1) * sizeof(WCHAR) ); 7135 break; 7136 } 7137 if (!*q) break; 7138 p = ++q; 7139 } 7140 7141 if (!new_value[0] || !value) 7142 { 7143 TRACE("removing %s\n", debugstr_w(name)); 7144 res = RegDeleteValueW( env, name ); 7145 if (res != ERROR_SUCCESS) 7146 WARN( "failed to delete value %s (%ld)\n", debugstr_w(name), res ); 7147 } 7148 else 7149 { 7150 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(new_value)); 7151 size = (lstrlenW( new_value ) + 1) * sizeof(WCHAR); 7152 res = RegSetValueExW( env, name, 0, type, (BYTE *)new_value, size ); 7153 if (res != ERROR_SUCCESS) 7154 WARN( "failed to set %s to %s (%ld)\n", debugstr_w(name), debugstr_w(new_value), res ); 7155 } 7156 7157 done: 7158 uirow = MSI_CreateRecord( 3 ); 7159 MSI_RecordSetStringW( uirow, 1, name ); 7160 MSI_RecordSetStringW( uirow, 2, value ); 7161 MSI_RecordSetInteger( uirow, 3, action ); 7162 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 7163 msiobj_release( &uirow->hdr ); 7164 7165 if (env) RegCloseKey( env ); 7166 free( deformatted ); 7167 free( new_value ); 7168 return r; 7169 } 7170 7171 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package ) 7172 { 7173 MSIQUERY *view; 7174 UINT rc; 7175 7176 if (package->script == SCRIPT_NONE) 7177 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveEnvironmentStrings"); 7178 7179 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Environment`", &view ); 7180 if (rc != ERROR_SUCCESS) 7181 return ERROR_SUCCESS; 7182 7183 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package ); 7184 msiobj_release( &view->hdr ); 7185 return rc; 7186 } 7187 7188 UINT msi_validate_product_id( MSIPACKAGE *package ) 7189 { 7190 LPWSTR key, template, id; 7191 UINT r = ERROR_SUCCESS; 7192 7193 id = msi_dup_property( package->db, L"ProductID" ); 7194 if (id) 7195 { 7196 free( id ); 7197 return ERROR_SUCCESS; 7198 } 7199 template = msi_dup_property( package->db, L"PIDTemplate" ); 7200 key = msi_dup_property( package->db, L"PIDKEY" ); 7201 if (key && template) 7202 { 7203 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) ); 7204 #ifdef __REACTOS__ 7205 WARN("Product key validation HACK, see CORE-14710\n"); 7206 #else 7207 r = msi_set_property( package->db, L"ProductID", key, -1 ); 7208 #endif 7209 } 7210 free( template ); 7211 free( key ); 7212 return r; 7213 } 7214 7215 static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) 7216 { 7217 return msi_validate_product_id( package ); 7218 } 7219 7220 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package ) 7221 { 7222 TRACE("\n"); 7223 package->need_reboot_at_end = 1; 7224 return ERROR_SUCCESS; 7225 } 7226 7227 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package ) 7228 { 7229 MSIRECORD *uirow; 7230 int space = msi_get_property_int( package->db, L"AVAILABLEFREEREG", 0 ); 7231 7232 TRACE("%p %d kilobytes\n", package, space); 7233 7234 uirow = MSI_CreateRecord( 1 ); 7235 MSI_RecordSetInteger( uirow, 1, space ); 7236 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 7237 msiobj_release( &uirow->hdr ); 7238 7239 return ERROR_SUCCESS; 7240 } 7241 7242 static UINT ACTION_DisableRollback( MSIPACKAGE *package ) 7243 { 7244 TRACE("%p\n", package); 7245 7246 msi_set_property( package->db, L"RollbackDisabled", L"1", -1 ); 7247 return ERROR_SUCCESS; 7248 } 7249 7250 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package ) 7251 { 7252 FIXME("%p\n", package); 7253 return ERROR_SUCCESS; 7254 } 7255 7256 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package ) 7257 { 7258 MSIQUERY *view; 7259 UINT r; 7260 DWORD count; 7261 7262 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDriver`", &view ); 7263 if (r == ERROR_SUCCESS) 7264 { 7265 count = 0; 7266 r = MSI_IterateRecords( view, &count, NULL, package ); 7267 msiobj_release( &view->hdr ); 7268 if (r != ERROR_SUCCESS) 7269 return r; 7270 if (count) FIXME( "ignored %lu rows in ODBCDriver table\n", count ); 7271 } 7272 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCTranslator`", &view ); 7273 if (r == ERROR_SUCCESS) 7274 { 7275 count = 0; 7276 r = MSI_IterateRecords( view, &count, NULL, package ); 7277 msiobj_release( &view->hdr ); 7278 if (r != ERROR_SUCCESS) 7279 return r; 7280 if (count) FIXME( "ignored %lu rows in ODBCTranslator table\n", count ); 7281 } 7282 return ERROR_SUCCESS; 7283 } 7284 7285 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param ) 7286 { 7287 MSIPACKAGE *package = param; 7288 const WCHAR *property = MSI_RecordGetString( rec, 7 ); 7289 int attrs = MSI_RecordGetInteger( rec, 5 ); 7290 UINT len = ARRAY_SIZE( L"msiexec /qn /i %s REMOVE=%s" ); 7291 WCHAR *product, *features, *cmd; 7292 STARTUPINFOW si; 7293 PROCESS_INFORMATION info; 7294 BOOL ret; 7295 7296 if (attrs & msidbUpgradeAttributesOnlyDetect) return ERROR_SUCCESS; 7297 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS; 7298 7299 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features ); 7300 7301 len += lstrlenW( product ); 7302 if (features) 7303 len += lstrlenW( features ); 7304 else 7305 len += ARRAY_SIZE( L"ALL" ); 7306 7307 if (!(cmd = malloc( len * sizeof(WCHAR) ))) 7308 { 7309 free( product ); 7310 free( features ); 7311 return ERROR_OUTOFMEMORY; 7312 } 7313 swprintf( cmd, len, L"msiexec /qn /i %s REMOVE=%s", product, features ? features : L"ALL" ); 7314 free( product ); 7315 free( features ); 7316 7317 memset( &si, 0, sizeof(STARTUPINFOW) ); 7318 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info ); 7319 free( cmd ); 7320 if (!ret) return GetLastError(); 7321 CloseHandle( info.hThread ); 7322 7323 WaitForSingleObject( info.hProcess, INFINITE ); 7324 CloseHandle( info.hProcess ); 7325 return ERROR_SUCCESS; 7326 } 7327 7328 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package ) 7329 { 7330 MSIQUERY *view; 7331 UINT r; 7332 7333 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Upgrade`", &view ); 7334 if (r == ERROR_SUCCESS) 7335 { 7336 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package ); 7337 msiobj_release( &view->hdr ); 7338 if (r != ERROR_SUCCESS) 7339 return r; 7340 } 7341 return ERROR_SUCCESS; 7342 } 7343 7344 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param ) 7345 { 7346 MSIPACKAGE *package = param; 7347 int attributes = MSI_RecordGetInteger( rec, 5 ); 7348 7349 if (attributes & msidbUpgradeAttributesMigrateFeatures) 7350 { 7351 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 ); 7352 const WCHAR *version_min = MSI_RecordGetString( rec, 2 ); 7353 const WCHAR *version_max = MSI_RecordGetString( rec, 3 ); 7354 const WCHAR *language = MSI_RecordGetString( rec, 4 ); 7355 HKEY hkey; 7356 UINT r; 7357 7358 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 7359 { 7360 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE ); 7361 if (r != ERROR_SUCCESS) 7362 return ERROR_SUCCESS; 7363 } 7364 else 7365 { 7366 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE ); 7367 if (r != ERROR_SUCCESS) 7368 return ERROR_SUCCESS; 7369 } 7370 RegCloseKey( hkey ); 7371 7372 FIXME("migrate feature states from %s version min %s version max %s language %s\n", 7373 debugstr_w(upgrade_code), debugstr_w(version_min), 7374 debugstr_w(version_max), debugstr_w(language)); 7375 } 7376 return ERROR_SUCCESS; 7377 } 7378 7379 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package ) 7380 { 7381 MSIQUERY *view; 7382 UINT r; 7383 7384 if (msi_get_property_int( package->db, L"Installed", 0 )) 7385 { 7386 TRACE("product is installed, skipping action\n"); 7387 return ERROR_SUCCESS; 7388 } 7389 if (msi_get_property_int( package->db, L"Preselected", 0 )) 7390 { 7391 TRACE("Preselected property is set, not migrating feature states\n"); 7392 return ERROR_SUCCESS; 7393 } 7394 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Upgrade`", &view ); 7395 if (r == ERROR_SUCCESS) 7396 { 7397 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package ); 7398 msiobj_release( &view->hdr ); 7399 if (r != ERROR_SUCCESS) 7400 return r; 7401 } 7402 return ERROR_SUCCESS; 7403 } 7404 7405 static void bind_image( MSIPACKAGE *package, const char *filename, const char *path ) 7406 { 7407 msi_disable_fs_redirection( package ); 7408 if (!BindImage( filename, path, NULL )) WARN( "failed to bind image %lu\n", GetLastError() ); 7409 msi_revert_fs_redirection( package ); 7410 } 7411 7412 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param ) 7413 { 7414 UINT i; 7415 MSIFILE *file; 7416 MSIPACKAGE *package = param; 7417 const WCHAR *key = MSI_RecordGetString( rec, 1 ); 7418 const WCHAR *paths = MSI_RecordGetString( rec, 2 ); 7419 char *filenameA, *pathA; 7420 WCHAR *pathW, **path_list; 7421 7422 if (!(file = msi_get_loaded_file( package, key ))) 7423 { 7424 WARN("file %s not found\n", debugstr_w(key)); 7425 return ERROR_SUCCESS; 7426 } 7427 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS; 7428 7429 path_list = msi_split_string( paths, ';' ); 7430 if (!path_list) bind_image( package, filenameA, NULL ); 7431 else 7432 { 7433 for (i = 0; path_list[i] && path_list[i][0]; i++) 7434 { 7435 deformat_string( package, path_list[i], &pathW ); 7436 if ((pathA = strdupWtoA( pathW ))) 7437 { 7438 bind_image( package, filenameA, pathA ); 7439 free( pathA ); 7440 } 7441 free( pathW ); 7442 } 7443 } 7444 free( path_list ); 7445 free( filenameA ); 7446 7447 return ERROR_SUCCESS; 7448 } 7449 7450 static UINT ACTION_BindImage( MSIPACKAGE *package ) 7451 { 7452 MSIQUERY *view; 7453 UINT r; 7454 7455 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `BindImage`", &view ); 7456 if (r == ERROR_SUCCESS) 7457 { 7458 MSI_IterateRecords( view, NULL, ITERATE_BindImage, package ); 7459 msiobj_release( &view->hdr ); 7460 } 7461 return ERROR_SUCCESS; 7462 } 7463 7464 static UINT unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table ) 7465 { 7466 MSIQUERY *view; 7467 DWORD count = 0; 7468 UINT r; 7469 7470 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s`", table ); 7471 if (r == ERROR_SUCCESS) 7472 { 7473 r = MSI_IterateRecords(view, &count, NULL, package); 7474 msiobj_release(&view->hdr); 7475 if (r != ERROR_SUCCESS) 7476 return r; 7477 } 7478 if (count) FIXME( "%s: ignored %lu rows from %s\n", action, count, debugstr_w(table) ); 7479 return ERROR_SUCCESS; 7480 } 7481 7482 static UINT ACTION_IsolateComponents( MSIPACKAGE *package ) 7483 { 7484 return unimplemented_action_stub( package, "IsolateComponents", L"IsolateComponent" ); 7485 } 7486 7487 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package ) 7488 { 7489 return unimplemented_action_stub( package, "RMCCPSearch", L"CCPSearch" ); 7490 } 7491 7492 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package ) 7493 { 7494 return unimplemented_action_stub( package, "RegisterComPlus", L"Complus" ); 7495 } 7496 7497 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package ) 7498 { 7499 return unimplemented_action_stub( package, "UnregisterComPlus", L"Complus" ); 7500 } 7501 7502 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package ) 7503 { 7504 return unimplemented_action_stub( package, "InstallSFPCatalogFile", L"SFPCatalog" ); 7505 } 7506 7507 static const struct 7508 { 7509 const WCHAR *action; 7510 const UINT description; 7511 const UINT template; 7512 UINT (*handler)(MSIPACKAGE *); 7513 const WCHAR *action_rollback; 7514 } 7515 StandardActions[] = 7516 { 7517 { L"AllocateRegistrySpace", IDS_DESC_ALLOCATEREGISTRYSPACE, IDS_TEMP_ALLOCATEREGISTRYSPACE, ACTION_AllocateRegistrySpace, NULL }, 7518 { L"AppSearch", IDS_DESC_APPSEARCH, IDS_TEMP_APPSEARCH, ACTION_AppSearch, NULL }, 7519 { L"BindImage", IDS_DESC_BINDIMAGE, IDS_TEMP_BINDIMAGE, ACTION_BindImage, NULL }, 7520 { L"CCPSearch", IDS_DESC_CCPSEARCH, 0, ACTION_CCPSearch, NULL }, 7521 { L"CostFinalize", IDS_DESC_COSTFINALIZE, 0, ACTION_CostFinalize, NULL }, 7522 { L"CostInitialize", IDS_DESC_COSTINITIALIZE, 0, ACTION_CostInitialize, NULL }, 7523 { L"CreateFolders", IDS_DESC_CREATEFOLDERS, IDS_TEMP_CREATEFOLDERS, ACTION_CreateFolders, L"RemoveFolders" }, 7524 { L"CreateShortcuts", IDS_DESC_CREATESHORTCUTS, IDS_TEMP_CREATESHORTCUTS, ACTION_CreateShortcuts, L"RemoveShortcuts" }, 7525 { L"DeleteServices", IDS_DESC_DELETESERVICES, IDS_TEMP_DELETESERVICES, ACTION_DeleteServices, L"InstallServices" }, 7526 { L"DisableRollback", 0, 0, ACTION_DisableRollback, NULL }, 7527 { L"DuplicateFiles", IDS_DESC_DUPLICATEFILES, IDS_TEMP_DUPLICATEFILES, ACTION_DuplicateFiles, L"RemoveDuplicateFiles" }, 7528 { L"ExecuteAction", 0, 0, ACTION_ExecuteAction, NULL }, 7529 { L"FileCost", IDS_DESC_FILECOST, 0, ACTION_FileCost, NULL }, 7530 { L"FindRelatedProducts", IDS_DESC_FINDRELATEDPRODUCTS, IDS_TEMP_FINDRELATEDPRODUCTS, ACTION_FindRelatedProducts, NULL }, 7531 { L"ForceReboot", 0, 0, ACTION_ForceReboot, NULL }, 7532 { L"InstallAdminPackage", IDS_DESC_INSTALLADMINPACKAGE, IDS_TEMP_INSTALLADMINPACKAGE, ACTION_InstallAdminPackage, NULL }, 7533 { L"InstallExecute", 0, 0, ACTION_InstallExecute, NULL }, 7534 { L"InstallExecuteAgain", 0, 0, ACTION_InstallExecute, NULL }, 7535 { L"InstallFiles", IDS_DESC_INSTALLFILES, IDS_TEMP_INSTALLFILES, ACTION_InstallFiles, L"RemoveFiles" }, 7536 { L"InstallFinalize", 0, 0, ACTION_InstallFinalize, NULL }, 7537 { L"InstallInitialize", 0, 0, ACTION_InstallInitialize, NULL }, 7538 { L"InstallODBC", IDS_DESC_INSTALLODBC, 0, ACTION_InstallODBC, L"RemoveODBC" }, 7539 { L"InstallServices", IDS_DESC_INSTALLSERVICES, IDS_TEMP_INSTALLSERVICES, ACTION_InstallServices, L"DeleteServices" }, 7540 { L"InstallSFPCatalogFile", IDS_DESC_INSTALLSFPCATALOGFILE, IDS_TEMP_INSTALLSFPCATALOGFILE, ACTION_InstallSFPCatalogFile, NULL }, 7541 { L"InstallValidate", IDS_DESC_INSTALLVALIDATE, 0, ACTION_InstallValidate, NULL }, 7542 { L"IsolateComponents", 0, 0, ACTION_IsolateComponents, NULL }, 7543 { L"LaunchConditions", IDS_DESC_LAUNCHCONDITIONS, 0, ACTION_LaunchConditions, NULL }, 7544 { L"MigrateFeutureStates", IDS_DESC_MIGRATEFEATURESTATES, IDS_TEMP_MIGRATEFEATURESTATES, ACTION_MigrateFeatureStates, NULL }, 7545 { L"MoveFiles", IDS_DESC_MOVEFILES, IDS_TEMP_MOVEFILES, ACTION_MoveFiles, NULL }, 7546 { L"MsiPublishAssemblies", IDS_DESC_MSIPUBLISHASSEMBLIES, IDS_TEMP_MSIPUBLISHASSEMBLIES, ACTION_MsiPublishAssemblies, L"MsiUnpublishAssemblies" }, 7547 { L"MsiUnpublishAssemblies", IDS_DESC_MSIUNPUBLISHASSEMBLIES, IDS_TEMP_MSIUNPUBLISHASSEMBLIES, ACTION_MsiUnpublishAssemblies, L"MsiPublishAssemblies" }, 7548 { L"PatchFiles", IDS_DESC_PATCHFILES, IDS_TEMP_PATCHFILES, ACTION_PatchFiles, NULL }, 7549 { L"ProcessComponents", IDS_DESC_PROCESSCOMPONENTS, 0, ACTION_ProcessComponents, L"ProcessComponents" }, 7550 { L"PublishComponents", IDS_DESC_PUBLISHCOMPONENTS, IDS_TEMP_PUBLISHCOMPONENTS, ACTION_PublishComponents, L"UnpublishComponents" }, 7551 { L"PublishFeatures", IDS_DESC_PUBLISHFEATURES, IDS_TEMP_PUBLISHFEATURES, ACTION_PublishFeatures, L"UnpublishFeatures" }, 7552 { L"PublishProduct", IDS_DESC_PUBLISHPRODUCT, 0, ACTION_PublishProduct, L"UnpublishProduct" }, 7553 { L"RegisterClassInfo", IDS_DESC_REGISTERCLASSINFO, IDS_TEMP_REGISTERCLASSINFO, ACTION_RegisterClassInfo, L"UnregisterClassInfo" }, 7554 { L"RegisterComPlus", IDS_DESC_REGISTERCOMPLUS, IDS_TEMP_REGISTERCOMPLUS, ACTION_RegisterComPlus, L"UnregisterComPlus" }, 7555 { L"RegisterExtensionInfo", IDS_DESC_REGISTEREXTENSIONINFO, 0, ACTION_RegisterExtensionInfo, L"UnregisterExtensionInfo" }, 7556 { L"RegisterFonts", IDS_DESC_REGISTERFONTS, IDS_TEMP_REGISTERFONTS, ACTION_RegisterFonts, L"UnregisterFonts" }, 7557 { L"RegisterMIMEInfo", IDS_DESC_REGISTERMIMEINFO, IDS_TEMP_REGISTERMIMEINFO, ACTION_RegisterMIMEInfo, L"UnregisterMIMEInfo" }, 7558 { L"RegisterProduct", IDS_DESC_REGISTERPRODUCT, 0, ACTION_RegisterProduct, NULL }, 7559 { L"RegisterProgIdInfo", IDS_DESC_REGISTERPROGIDINFO, IDS_TEMP_REGISTERPROGIDINFO, ACTION_RegisterProgIdInfo, L"UnregisterProgIdInfo" }, 7560 { L"RegisterTypeLibraries", IDS_DESC_REGISTERTYPELIBRARIES, IDS_TEMP_REGISTERTYPELIBRARIES, ACTION_RegisterTypeLibraries, L"UnregisterTypeLibraries" }, 7561 { L"RegisterUser", IDS_DESC_REGISTERUSER, 0, ACTION_RegisterUser, NULL }, 7562 { L"RemoveDuplicateFiles", IDS_DESC_REMOVEDUPLICATEFILES, IDS_TEMP_REMOVEDUPLICATEFILES, ACTION_RemoveDuplicateFiles, L"DuplicateFiles" }, 7563 { L"RemoveEnvironmentStrings", IDS_DESC_REMOVEENVIRONMENTSTRINGS, IDS_TEMP_REMOVEENVIRONMENTSTRINGS, ACTION_RemoveEnvironmentStrings, L"WriteEnvironmentStrings" }, 7564 { L"RemoveExistingProducts", IDS_DESC_REMOVEEXISTINGPRODUCTS, IDS_TEMP_REMOVEEXISTINGPRODUCTS, ACTION_RemoveExistingProducts, NULL }, 7565 { L"RemoveFiles", IDS_DESC_REMOVEFILES, IDS_TEMP_REMOVEFILES, ACTION_RemoveFiles, L"InstallFiles" }, 7566 { L"RemoveFolders", IDS_DESC_REMOVEFOLDERS, IDS_TEMP_REMOVEFOLDERS, ACTION_RemoveFolders, L"CreateFolders" }, 7567 { L"RemoveIniValues", IDS_DESC_REMOVEINIVALUES, IDS_TEMP_REMOVEINIVALUES, ACTION_RemoveIniValues, L"WriteIniValues" }, 7568 { L"RemoveODBC", IDS_DESC_REMOVEODBC, 0, ACTION_RemoveODBC, L"InstallODBC" }, 7569 { L"RemoveRegistryValues", IDS_DESC_REMOVEREGISTRYVALUES, IDS_TEMP_REMOVEREGISTRYVALUES, ACTION_RemoveRegistryValues, L"WriteRegistryValues" }, 7570 { L"RemoveShortcuts", IDS_DESC_REMOVESHORTCUTS, IDS_TEMP_REMOVESHORTCUTS, ACTION_RemoveShortcuts, L"CreateShortcuts" }, 7571 { L"ResolveSource", 0, 0, ACTION_ResolveSource, NULL }, 7572 { L"RMCCPSearch", IDS_DESC_RMCCPSEARCH, 0, ACTION_RMCCPSearch, NULL }, 7573 { L"ScheduleReboot", 0, 0, ACTION_ScheduleReboot, NULL }, 7574 { L"SelfRegModules", IDS_DESC_SELFREGMODULES, IDS_TEMP_SELFREGMODULES, ACTION_SelfRegModules, L"SelfUnregModules" }, 7575 { L"SelfUnregModules", IDS_DESC_SELFUNREGMODULES, IDS_TEMP_SELFUNREGMODULES, ACTION_SelfUnregModules, L"SelfRegModules" }, 7576 { L"SetODBCFolders", IDS_DESC_SETODBCFOLDERS, 0, ACTION_SetODBCFolders, NULL }, 7577 { L"StartServices", IDS_DESC_STARTSERVICES, IDS_TEMP_STARTSERVICES, ACTION_StartServices, L"StopServices" }, 7578 { L"StopServices", IDS_DESC_STOPSERVICES, IDS_TEMP_STOPSERVICES, ACTION_StopServices, L"StartServices" }, 7579 { L"UnpublishComponents", IDS_DESC_UNPUBLISHCOMPONENTS, IDS_TEMP_UNPUBLISHCOMPONENTS, ACTION_UnpublishComponents, L"PublishComponents" }, 7580 { L"UnpublishFeatures", IDS_DESC_UNPUBLISHFEATURES, IDS_TEMP_UNPUBLISHFEATURES, ACTION_UnpublishFeatures, L"PublishFeatures" }, 7581 { L"UnpublishProduct", IDS_DESC_UNPUBLISHPRODUCT, 0, ACTION_UnpublishProduct, NULL }, /* for rollback only */ 7582 { L"UnregisterClassInfo", IDS_DESC_UNREGISTERCLASSINFO, IDS_TEMP_UNREGISTERCLASSINFO, ACTION_UnregisterClassInfo, L"RegisterClassInfo" }, 7583 { L"UnregisterComPlus", IDS_DESC_UNREGISTERCOMPLUS, IDS_TEMP_UNREGISTERCOMPLUS, ACTION_UnregisterComPlus, L"RegisterComPlus" }, 7584 { L"UnregisterExtensionInfo", IDS_DESC_UNREGISTEREXTENSIONINFO, IDS_TEMP_UNREGISTEREXTENSIONINFO, ACTION_UnregisterExtensionInfo, L"RegisterExtensionInfo" }, 7585 { L"UnregisterFonts", IDS_DESC_UNREGISTERFONTS, IDS_TEMP_UNREGISTERFONTS, ACTION_UnregisterFonts, L"RegisterFonts" }, 7586 { L"UnregisterMIMEInfo", IDS_DESC_UNREGISTERMIMEINFO, IDS_TEMP_UNREGISTERMIMEINFO, ACTION_UnregisterMIMEInfo, L"RegisterMIMEInfo" }, 7587 { L"UnregisterProgIdInfo", IDS_DESC_UNREGISTERPROGIDINFO, IDS_TEMP_UNREGISTERPROGIDINFO, ACTION_UnregisterProgIdInfo, L"RegisterProgIdInfo" }, 7588 { L"UnregisterTypeLibraries", IDS_DESC_UNREGISTERTYPELIBRARIES, IDS_TEMP_UNREGISTERTYPELIBRARIES, ACTION_UnregisterTypeLibraries, L"RegisterTypeLibraries" }, 7589 { L"ValidateProductID", 0, 0, ACTION_ValidateProductID, NULL }, 7590 { L"WriteEnvironmentStrings", IDS_DESC_WRITEENVIRONMENTSTRINGS, IDS_TEMP_WRITEENVIRONMENTSTRINGS, ACTION_WriteEnvironmentStrings, L"RemoveEnvironmentStrings" }, 7591 { L"WriteIniValues", IDS_DESC_WRITEINIVALUES, IDS_TEMP_WRITEINIVALUES, ACTION_WriteIniValues, L"RemoveIniValues" }, 7592 { L"WriteRegistryValues", IDS_DESC_WRITEREGISTRYVALUES, IDS_TEMP_WRITEREGISTRYVALUES, ACTION_WriteRegistryValues, L"RemoveRegistryValues" }, 7593 { L"INSTALL", 0, 0, ACTION_INSTALL, NULL }, 7594 { 0 } 7595 }; 7596 7597 static UINT ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action) 7598 { 7599 UINT rc = ERROR_FUNCTION_NOT_CALLED; 7600 UINT i; 7601 7602 i = 0; 7603 while (StandardActions[i].action != NULL) 7604 { 7605 if (!wcscmp( StandardActions[i].action, action )) 7606 { 7607 WCHAR description[100] = {0}, template[100] = {0}; 7608 7609 if (StandardActions[i].description != 0) 7610 LoadStringW(msi_hInstance, StandardActions[i].description, (LPWSTR)&description, 100); 7611 if (StandardActions[i].template != 0) 7612 LoadStringW(msi_hInstance, StandardActions[i].template, (LPWSTR)&template, 100); 7613 7614 ui_actionstart(package, action, description, template); 7615 if (StandardActions[i].handler) 7616 { 7617 ui_actioninfo( package, action, TRUE, 0 ); 7618 rc = StandardActions[i].handler( package ); 7619 ui_actioninfo( package, action, FALSE, !rc ); 7620 7621 if (StandardActions[i].action_rollback && !package->need_rollback) 7622 { 7623 TRACE("scheduling rollback action\n"); 7624 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback ); 7625 } 7626 } 7627 else 7628 { 7629 FIXME("unhandled standard action %s\n", debugstr_w(action)); 7630 rc = ERROR_SUCCESS; 7631 } 7632 break; 7633 } 7634 i++; 7635 } 7636 7637 return rc; 7638 } 7639 7640 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) 7641 { 7642 UINT rc; 7643 7644 TRACE("Performing action (%s)\n", debugstr_w(action)); 7645 7646 package->action_progress_increment = 0; 7647 rc = ACTION_HandleStandardAction(package, action); 7648 7649 if (rc == ERROR_FUNCTION_NOT_CALLED) 7650 rc = ACTION_HandleCustomAction(package, action); 7651 7652 if (rc == ERROR_FUNCTION_NOT_CALLED) 7653 WARN("unhandled msi action %s\n", debugstr_w(action)); 7654 7655 return rc; 7656 } 7657 7658 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) 7659 { 7660 UINT rc = ERROR_SUCCESS; 7661 MSIRECORD *row; 7662 7663 if (needs_ui_sequence(package)) 7664 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` = %d", seq); 7665 else 7666 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` = %d", seq); 7667 7668 if (row) 7669 { 7670 LPCWSTR action, cond; 7671 7672 TRACE("Running the actions\n"); 7673 7674 /* check conditions */ 7675 cond = MSI_RecordGetString(row, 2); 7676 7677 /* this is a hack to skip errors in the condition code */ 7678 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) 7679 { 7680 msiobj_release(&row->hdr); 7681 return ERROR_SUCCESS; 7682 } 7683 7684 action = MSI_RecordGetString(row, 1); 7685 if (!action) 7686 { 7687 ERR("failed to fetch action\n"); 7688 msiobj_release(&row->hdr); 7689 return ERROR_FUNCTION_FAILED; 7690 } 7691 7692 rc = ACTION_PerformAction(package, action); 7693 7694 msiobj_release(&row->hdr); 7695 } 7696 7697 return rc; 7698 } 7699 7700 DWORD WINAPI dummy_thread_proc(void *arg) 7701 { 7702 struct dummy_thread *info = arg; 7703 HRESULT hr; 7704 7705 hr = CoInitializeEx(0, COINIT_MULTITHREADED); 7706 if (FAILED(hr)) ERR("CoInitializeEx failed %08x\n", hr); 7707 7708 SetEvent(info->started); 7709 WaitForSingleObject(info->stopped, INFINITE); 7710 7711 CoUninitialize(); 7712 return 0; 7713 } 7714 7715 static void start_dummy_thread(struct dummy_thread *info) 7716 { 7717 if (!(info->started = CreateEventA(NULL, TRUE, FALSE, NULL))) return; 7718 if (!(info->stopped = CreateEventA(NULL, TRUE, FALSE, NULL))) return; 7719 if (!(info->thread = CreateThread(NULL, 0, dummy_thread_proc, info, 0, NULL))) return; 7720 7721 WaitForSingleObject(info->started, INFINITE); 7722 } 7723 7724 static void stop_dummy_thread(struct dummy_thread *info) 7725 { 7726 if (info->thread) 7727 { 7728 SetEvent(info->stopped); 7729 WaitForSingleObject(info->thread, INFINITE); 7730 CloseHandle(info->thread); 7731 } 7732 if (info->started) CloseHandle(info->started); 7733 if (info->stopped) CloseHandle(info->stopped); 7734 } 7735 7736 /**************************************************** 7737 * TOP level entry points 7738 *****************************************************/ 7739 7740 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, 7741 LPCWSTR szCommandLine ) 7742 { 7743 WCHAR *reinstall = NULL, *productcode, *action; 7744 struct dummy_thread thread_info = {NULL, NULL, NULL}; 7745 UINT rc; 7746 DWORD len = 0; 7747 7748 if (szPackagePath) 7749 { 7750 LPWSTR p, dir; 7751 LPCWSTR file; 7752 7753 dir = wcsdup(szPackagePath); 7754 p = wcsrchr(dir, '\\'); 7755 if (p) 7756 { 7757 *(++p) = 0; 7758 file = szPackagePath + (p - dir); 7759 } 7760 else 7761 { 7762 free(dir); 7763 dir = malloc(MAX_PATH * sizeof(WCHAR)); 7764 GetCurrentDirectoryW(MAX_PATH, dir); 7765 lstrcatW(dir, L"\\"); 7766 file = szPackagePath; 7767 } 7768 7769 free(package->PackagePath); 7770 package->PackagePath = malloc((wcslen(dir) + wcslen(file) + 1) * sizeof(WCHAR)); 7771 if (!package->PackagePath) 7772 { 7773 free(dir); 7774 return ERROR_OUTOFMEMORY; 7775 } 7776 7777 lstrcpyW(package->PackagePath, dir); 7778 lstrcatW(package->PackagePath, file); 7779 free(dir); 7780 7781 msi_set_sourcedir_props(package, FALSE); 7782 } 7783 7784 rc = msi_parse_command_line( package, szCommandLine, FALSE ); 7785 if (rc != ERROR_SUCCESS) 7786 return rc; 7787 7788 msi_apply_transforms( package ); 7789 msi_apply_patches( package ); 7790 7791 if (msi_get_property( package->db, L"ACTION", NULL, &len )) 7792 msi_set_property( package->db, L"ACTION", L"INSTALL", -1 ); 7793 action = msi_dup_property( package->db, L"ACTION" ); 7794 CharUpperW(action); 7795 7796 msi_set_original_database_property( package->db, szPackagePath ); 7797 msi_parse_command_line( package, szCommandLine, FALSE ); 7798 msi_adjust_privilege_properties( package ); 7799 msi_set_context( package ); 7800 7801 start_dummy_thread(&thread_info); 7802 7803 productcode = msi_dup_property( package->db, L"ProductCode" ); 7804 if (wcsicmp( productcode, package->ProductCode )) 7805 { 7806 TRACE( "product code changed %s -> %s\n", debugstr_w(package->ProductCode), debugstr_w(productcode) ); 7807 free( package->ProductCode ); 7808 package->ProductCode = productcode; 7809 } 7810 else free( productcode ); 7811 7812 if (msi_get_property_int( package->db, L"DISABLEROLLBACK", 0 )) 7813 { 7814 TRACE("disabling rollback\n"); 7815 msi_set_property( package->db, L"RollbackDisabled", L"1", -1 ); 7816 } 7817 7818 rc = ACTION_PerformAction(package, action); 7819 7820 /* process the ending type action */ 7821 if (rc == ERROR_SUCCESS) 7822 ACTION_PerformActionSequence(package, -1); 7823 else if (rc == ERROR_INSTALL_USEREXIT) 7824 ACTION_PerformActionSequence(package, -2); 7825 else if (rc == ERROR_INSTALL_SUSPEND) 7826 ACTION_PerformActionSequence(package, -4); 7827 else /* failed */ 7828 { 7829 ACTION_PerformActionSequence(package, -3); 7830 if (!msi_get_property_int( package->db, L"RollbackDisabled", 0 )) 7831 { 7832 package->need_rollback = TRUE; 7833 } 7834 } 7835 7836 /* finish up running custom actions */ 7837 ACTION_FinishCustomActions(package); 7838 7839 stop_dummy_thread(&thread_info); 7840 7841 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, L"REINSTALL" ))) 7842 { 7843 WARN("installation failed, running rollback script\n"); 7844 execute_script( package, SCRIPT_ROLLBACK ); 7845 } 7846 free( reinstall ); 7847 free( action ); 7848 7849 if (rc == ERROR_SUCCESS && package->need_reboot_at_end) 7850 return ERROR_SUCCESS_REBOOT_REQUIRED; 7851 7852 return rc; 7853 } 7854