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