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