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