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