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