1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2010 Hans Leidekker 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 "winreg.h" 28 #include "wine/debug.h" 29 #include "msipriv.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(msi); 32 33 static BOOL load_fusion_dlls( MSIPACKAGE *package ) 34 { 35 HRESULT (WINAPI *pLoadLibraryShim)( const WCHAR *, const WCHAR *, void *, HMODULE * ); 36 WCHAR path[MAX_PATH]; 37 DWORD len = GetSystemDirectoryW( path, MAX_PATH ); 38 39 lstrcpyW( path + len, L"\\mscoree.dll" ); 40 if (package->hmscoree || !(package->hmscoree = LoadLibraryW( path ))) return TRUE; 41 if (!(pLoadLibraryShim = (void *)GetProcAddress( package->hmscoree, "LoadLibraryShim" ))) 42 { 43 FreeLibrary( package->hmscoree ); 44 package->hmscoree = NULL; 45 return TRUE; 46 } 47 48 pLoadLibraryShim( L"fusion.dll", L"v1.0.3705", NULL, &package->hfusion10 ); 49 pLoadLibraryShim( L"fusion.dll", L"v1.1.4322", NULL, &package->hfusion11 ); 50 pLoadLibraryShim( L"fusion.dll", L"v2.0.50727", NULL, &package->hfusion20 ); 51 pLoadLibraryShim( L"fusion.dll", L"v4.0.30319", NULL, &package->hfusion40 ); 52 53 return TRUE; 54 } 55 56 BOOL msi_init_assembly_caches( MSIPACKAGE *package ) 57 { 58 HRESULT (WINAPI *pCreateAssemblyCache)( IAssemblyCache **, DWORD ); 59 60 if (package->cache_sxs) return TRUE; 61 if (CreateAssemblyCache( &package->cache_sxs, 0 ) != S_OK) return FALSE; 62 63 if (!load_fusion_dlls( package )) return FALSE; 64 package->pGetFileVersion = (void *)GetProcAddress( package->hmscoree, "GetFileVersion" ); /* missing from v1.0.3705 */ 65 66 if (package->hfusion10) 67 { 68 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion10, "CreateAssemblyCache" ); 69 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V10], 0 ); 70 } 71 if (package->hfusion11) 72 { 73 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion11, "CreateAssemblyCache" ); 74 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V11], 0 ); 75 } 76 if (package->hfusion20) 77 { 78 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion20, "CreateAssemblyCache" ); 79 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V20], 0 ); 80 } 81 if (package->hfusion40) 82 { 83 pCreateAssemblyCache = (void *)GetProcAddress( package->hfusion40, "CreateAssemblyCache" ); 84 pCreateAssemblyCache( &package->cache_net[CLR_VERSION_V40], 0 ); 85 package->pCreateAssemblyNameObject = (void *)GetProcAddress( package->hfusion40, "CreateAssemblyNameObject" ); 86 package->pCreateAssemblyEnum = (void *)GetProcAddress( package->hfusion40, "CreateAssemblyEnum" ); 87 } 88 89 return TRUE; 90 } 91 92 void msi_destroy_assembly_caches( MSIPACKAGE *package ) 93 { 94 UINT i; 95 96 if (package->cache_sxs) 97 { 98 IAssemblyCache_Release( package->cache_sxs ); 99 package->cache_sxs = NULL; 100 } 101 for (i = 0; i < CLR_VERSION_MAX; i++) 102 { 103 if (package->cache_net[i]) 104 { 105 IAssemblyCache_Release( package->cache_net[i] ); 106 package->cache_net[i] = NULL; 107 } 108 } 109 package->pGetFileVersion = NULL; 110 package->pCreateAssemblyNameObject = NULL; 111 package->pCreateAssemblyEnum = NULL; 112 FreeLibrary( package->hfusion10 ); 113 FreeLibrary( package->hfusion11 ); 114 FreeLibrary( package->hfusion20 ); 115 FreeLibrary( package->hfusion40 ); 116 FreeLibrary( package->hmscoree ); 117 package->hfusion10 = NULL; 118 package->hfusion11 = NULL; 119 package->hfusion20 = NULL; 120 package->hfusion40 = NULL; 121 package->hmscoree = NULL; 122 } 123 124 static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp ) 125 { 126 MSIQUERY *view; 127 MSIRECORD *rec; 128 UINT r; 129 130 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `MsiAssembly` WHERE `Component_` = '%s'", comp ); 131 if (r != ERROR_SUCCESS) 132 return NULL; 133 134 r = MSI_ViewExecute( view, NULL ); 135 if (r != ERROR_SUCCESS) 136 { 137 msiobj_release( &view->hdr ); 138 return NULL; 139 } 140 r = MSI_ViewFetch( view, &rec ); 141 if (r != ERROR_SUCCESS) 142 { 143 msiobj_release( &view->hdr ); 144 return NULL; 145 } 146 if (!MSI_RecordGetString( rec, 4 )) 147 TRACE("component is a global assembly\n"); 148 149 msiobj_release( &view->hdr ); 150 return rec; 151 } 152 153 struct assembly_name 154 { 155 DWORD count; 156 UINT index; 157 WCHAR **attrs; 158 }; 159 160 static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param ) 161 { 162 struct assembly_name *name = param; 163 const WCHAR *attr = MSI_RecordGetString( rec, 2 ); 164 const WCHAR *value = MSI_RecordGetString( rec, 3 ); 165 int len = lstrlenW( L"%s=\"%s\"" ) + lstrlenW( attr ) + lstrlenW( value ); 166 167 if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) ))) 168 return ERROR_OUTOFMEMORY; 169 170 if (!wcsicmp( attr, L"name" )) lstrcpyW( name->attrs[name->index++], value ); 171 else swprintf( name->attrs[name->index++], len, L"%s=\"%s\"", attr, value ); 172 return ERROR_SUCCESS; 173 } 174 175 static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly ) 176 { 177 struct assembly_name name; 178 WCHAR *display_name = NULL; 179 MSIQUERY *view; 180 UINT i, r; 181 int len; 182 183 r = MSI_OpenQuery( db, &view, L"SELECT * FROM `MsiAssemblyName` WHERE `Component_` = '%s'", comp ); 184 if (r != ERROR_SUCCESS) 185 return NULL; 186 187 name.count = 0; 188 name.index = 0; 189 name.attrs = NULL; 190 MSI_IterateRecords( view, &name.count, NULL, NULL ); 191 if (!name.count) goto done; 192 193 name.attrs = msi_alloc( name.count * sizeof(WCHAR *) ); 194 if (!name.attrs) goto done; 195 196 MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name ); 197 198 len = 0; 199 for (i = 0; i < name.count; i++) len += lstrlenW( name.attrs[i] ) + 1; 200 201 display_name = msi_alloc( (len + 1) * sizeof(WCHAR) ); 202 if (display_name) 203 { 204 display_name[0] = 0; 205 for (i = 0; i < name.count; i++) 206 { 207 lstrcatW( display_name, name.attrs[i] ); 208 if (i < name.count - 1) lstrcatW( display_name, L"," ); 209 } 210 } 211 212 done: 213 msiobj_release( &view->hdr ); 214 if (name.attrs) 215 { 216 for (i = 0; i < name.count; i++) msi_free( name.attrs[i] ); 217 msi_free( name.attrs ); 218 } 219 return display_name; 220 } 221 222 static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name ) 223 { 224 HRESULT hr; 225 ASSEMBLY_INFO info; 226 227 if (!cache) return FALSE; 228 229 memset( &info, 0, sizeof(info) ); 230 info.cbAssemblyInfo = sizeof(info); 231 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info ); 232 if (hr == S_OK /* sxs version */ || hr == E_NOT_SUFFICIENT_BUFFER) 233 { 234 return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED); 235 } 236 TRACE( "QueryAssemblyInfo returned %#lx\n", hr ); 237 return FALSE; 238 } 239 240 WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname ) 241 { 242 HRESULT hr; 243 ASSEMBLY_INFO info; 244 IAssemblyCache *cache = package->cache_net[CLR_VERSION_V40]; 245 246 if (!cache) return NULL; 247 248 memset( &info, 0, sizeof(info) ); 249 info.cbAssemblyInfo = sizeof(info); 250 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info ); 251 if (hr != E_NOT_SUFFICIENT_BUFFER) return NULL; 252 253 if (!(info.pszCurrentAssemblyPathBuf = msi_alloc( info.cchBuf * sizeof(WCHAR) ))) return NULL; 254 255 hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info ); 256 if (FAILED( hr )) 257 { 258 msi_free( info.pszCurrentAssemblyPathBuf ); 259 return NULL; 260 } 261 TRACE("returning %s\n", debugstr_w(info.pszCurrentAssemblyPathBuf)); 262 return info.pszCurrentAssemblyPathBuf; 263 } 264 265 IAssemblyEnum *msi_create_assembly_enum( MSIPACKAGE *package, const WCHAR *displayname ) 266 { 267 HRESULT hr; 268 IAssemblyName *name; 269 IAssemblyEnum *ret; 270 WCHAR *str; 271 DWORD len = 0; 272 273 if (!package->pCreateAssemblyNameObject || !package->pCreateAssemblyEnum) return NULL; 274 275 hr = package->pCreateAssemblyNameObject( &name, displayname, CANOF_PARSE_DISPLAY_NAME, NULL ); 276 if (FAILED( hr )) return NULL; 277 278 hr = IAssemblyName_GetName( name, &len, NULL ); 279 if (hr != E_NOT_SUFFICIENT_BUFFER || !(str = msi_alloc( len * sizeof(WCHAR) ))) 280 { 281 IAssemblyName_Release( name ); 282 return NULL; 283 } 284 285 hr = IAssemblyName_GetName( name, &len, str ); 286 IAssemblyName_Release( name ); 287 if (FAILED( hr )) 288 { 289 msi_free( str ); 290 return NULL; 291 } 292 293 hr = package->pCreateAssemblyNameObject( &name, str, 0, NULL ); 294 msi_free( str ); 295 if (FAILED( hr )) return NULL; 296 297 hr = package->pCreateAssemblyEnum( &ret, NULL, name, ASM_CACHE_GAC, NULL ); 298 IAssemblyName_Release( name ); 299 if (FAILED( hr )) return NULL; 300 301 return ret; 302 } 303 304 static const WCHAR *clr_version[] = 305 { 306 L"v1.0.3705", 307 L"v1.2.4322", 308 L"v2.0.50727", 309 L"v4.0.30319" 310 }; 311 312 static const WCHAR *get_clr_version_str( enum clr_version version ) 313 { 314 if (version >= ARRAY_SIZE( clr_version )) return L"unknown"; 315 return clr_version[version]; 316 } 317 318 /* assembly caches must be initialized */ 319 MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) 320 { 321 MSIRECORD *rec; 322 MSIASSEMBLY *a; 323 324 if (!(rec = get_assembly_record( package, comp->Component ))) return NULL; 325 if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) ))) 326 { 327 msiobj_release( &rec->hdr ); 328 return NULL; 329 } 330 a->feature = strdupW( MSI_RecordGetString( rec, 2 ) ); 331 TRACE("feature %s\n", debugstr_w(a->feature)); 332 333 a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) ); 334 TRACE("manifest %s\n", debugstr_w(a->manifest)); 335 336 a->application = strdupW( MSI_RecordGetString( rec, 4 ) ); 337 TRACE("application %s\n", debugstr_w(a->application)); 338 339 a->attributes = MSI_RecordGetInteger( rec, 5 ); 340 TRACE( "attributes %lu\n", a->attributes ); 341 342 if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a ))) 343 { 344 WARN("can't get display name\n"); 345 msiobj_release( &rec->hdr ); 346 msi_free( a->feature ); 347 msi_free( a->manifest ); 348 msi_free( a->application ); 349 msi_free( a ); 350 return NULL; 351 } 352 TRACE("display name %s\n", debugstr_w(a->display_name)); 353 354 if (a->application) 355 { 356 /* We can't check the manifest here because the target path may still change. 357 So we assume that the assembly is not installed and lean on the InstallFiles 358 action to determine which files need to be installed. 359 */ 360 a->installed = FALSE; 361 } 362 else 363 { 364 if (a->attributes == msidbAssemblyAttributesWin32) 365 a->installed = is_assembly_installed( package->cache_sxs, a->display_name ); 366 else 367 { 368 UINT i; 369 for (i = 0; i < CLR_VERSION_MAX; i++) 370 { 371 a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name ); 372 if (a->clr_version[i]) 373 { 374 TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i ))); 375 a->installed = TRUE; 376 break; 377 } 378 } 379 } 380 } 381 TRACE("assembly is %s\n", a->installed ? "installed" : "not installed"); 382 msiobj_release( &rec->hdr ); 383 return a; 384 } 385 386 static enum clr_version get_clr_version( MSIPACKAGE *package, const WCHAR *filename ) 387 { 388 DWORD len; 389 HRESULT hr; 390 enum clr_version version = CLR_VERSION_V11; 391 WCHAR *strW; 392 393 if (!package->pGetFileVersion) return CLR_VERSION_V10; 394 395 hr = package->pGetFileVersion( filename, NULL, 0, &len ); 396 if (hr != E_NOT_SUFFICIENT_BUFFER) return CLR_VERSION_V11; 397 if ((strW = msi_alloc( len * sizeof(WCHAR) ))) 398 { 399 hr = package->pGetFileVersion( filename, strW, len, &len ); 400 if (hr == S_OK) 401 { 402 UINT i; 403 for (i = 0; i < CLR_VERSION_MAX; i++) 404 if (!wcscmp( strW, clr_version[i] )) version = i; 405 } 406 msi_free( strW ); 407 } 408 return version; 409 } 410 411 UINT msi_install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) 412 { 413 HRESULT hr; 414 const WCHAR *manifest; 415 IAssemblyCache *cache; 416 MSIASSEMBLY *assembly = comp->assembly; 417 MSIFEATURE *feature = NULL; 418 419 if (comp->assembly->feature) 420 feature = msi_get_loaded_feature( package, comp->assembly->feature ); 421 422 if (assembly->application) 423 { 424 if (feature) feature->Action = INSTALLSTATE_LOCAL; 425 return ERROR_SUCCESS; 426 } 427 if (assembly->attributes == msidbAssemblyAttributesWin32) 428 { 429 if (!assembly->manifest) 430 { 431 WARN("no manifest\n"); 432 return ERROR_FUNCTION_FAILED; 433 } 434 manifest = msi_get_loaded_file( package, assembly->manifest )->TargetPath; 435 cache = package->cache_sxs; 436 } 437 else 438 { 439 manifest = msi_get_loaded_file( package, comp->KeyPath )->TargetPath; 440 cache = package->cache_net[get_clr_version( package, manifest )]; 441 if (!cache) return ERROR_SUCCESS; 442 } 443 TRACE("installing assembly %s\n", debugstr_w(manifest)); 444 445 hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL ); 446 if (hr != S_OK) 447 { 448 ERR( "failed to install assembly %s (%#lx)\n", debugstr_w(manifest), hr ); 449 return ERROR_FUNCTION_FAILED; 450 } 451 if (feature) feature->Action = INSTALLSTATE_LOCAL; 452 assembly->installed = TRUE; 453 return ERROR_SUCCESS; 454 } 455 456 UINT msi_uninstall_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) 457 { 458 HRESULT hr; 459 IAssemblyCache *cache; 460 MSIASSEMBLY *assembly = comp->assembly; 461 MSIFEATURE *feature = NULL; 462 463 if (comp->assembly->feature) 464 feature = msi_get_loaded_feature( package, comp->assembly->feature ); 465 466 if (assembly->application) 467 { 468 if (feature) feature->Action = INSTALLSTATE_ABSENT; 469 return ERROR_SUCCESS; 470 } 471 TRACE("removing %s\n", debugstr_w(assembly->display_name)); 472 473 if (assembly->attributes == msidbAssemblyAttributesWin32) 474 { 475 cache = package->cache_sxs; 476 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL ); 477 if (FAILED( hr )) WARN( "failed to uninstall assembly %#lx\n", hr ); 478 } 479 else 480 { 481 unsigned int i; 482 for (i = 0; i < CLR_VERSION_MAX; i++) 483 { 484 if (!assembly->clr_version[i]) continue; 485 cache = package->cache_net[i]; 486 if (cache) 487 { 488 hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL ); 489 if (FAILED( hr )) WARN( "failed to uninstall assembly %#lx\n", hr ); 490 } 491 } 492 } 493 if (feature) feature->Action = INSTALLSTATE_ABSENT; 494 assembly->installed = FALSE; 495 return ERROR_SUCCESS; 496 } 497 498 static WCHAR *build_local_assembly_path( const WCHAR *filename ) 499 { 500 UINT i; 501 WCHAR *ret; 502 503 if (!(ret = msi_alloc( (lstrlenW( filename ) + 1) * sizeof(WCHAR) ))) 504 return NULL; 505 506 for (i = 0; filename[i]; i++) 507 { 508 if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|'; 509 else ret[i] = filename[i]; 510 } 511 ret[i] = 0; 512 return ret; 513 } 514 515 static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey ) 516 { 517 HKEY root; 518 const WCHAR *path; 519 520 if (context == MSIINSTALLCONTEXT_MACHINE) 521 { 522 root = HKEY_CLASSES_ROOT; 523 if (win32) path = L"Installer\\Win32Assemblies\\"; 524 else path = L"Installer\\Assemblies\\"; 525 } 526 else 527 { 528 root = HKEY_CURRENT_USER; 529 if (win32) path = L"Software\\Microsoft\\Installer\\Win32Assemblies\\"; 530 else path = L"Software\\Microsoft\\Installer\\Assemblies\\"; 531 } 532 return RegCreateKeyW( root, path, hkey ); 533 } 534 535 static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey ) 536 { 537 LONG res; 538 HKEY root; 539 WCHAR *path; 540 541 if (!(path = build_local_assembly_path( filename ))) 542 return ERROR_OUTOFMEMORY; 543 544 if ((res = open_assemblies_key( context, win32, &root ))) 545 { 546 msi_free( path ); 547 return res; 548 } 549 res = RegCreateKeyW( root, path, hkey ); 550 RegCloseKey( root ); 551 msi_free( path ); 552 return res; 553 } 554 555 static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename ) 556 { 557 LONG res; 558 HKEY root; 559 WCHAR *path; 560 561 if (!(path = build_local_assembly_path( filename ))) 562 return ERROR_OUTOFMEMORY; 563 564 if ((res = open_assemblies_key( context, win32, &root ))) 565 { 566 msi_free( path ); 567 return res; 568 } 569 res = RegDeleteKeyW( root, path ); 570 RegCloseKey( root ); 571 msi_free( path ); 572 return res; 573 } 574 575 static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey ) 576 { 577 HKEY root; 578 const WCHAR *path; 579 580 if (context == MSIINSTALLCONTEXT_MACHINE) 581 { 582 root = HKEY_CLASSES_ROOT; 583 if (win32) path = L"Installer\\Win32Assemblies\\Global"; 584 else path = L"Installer\\Assemblies\\Global"; 585 } 586 else 587 { 588 root = HKEY_CURRENT_USER; 589 if (win32) path = L"Software\\Microsoft\\Installer\\Win32Assemblies\\Global"; 590 else path = L"Software\\Microsoft\\Installer\\Assemblies\\Global"; 591 } 592 return RegCreateKeyW( root, path, hkey ); 593 } 594 595 UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package ) 596 { 597 MSICOMPONENT *comp; 598 599 if (package->script == SCRIPT_NONE) 600 return msi_schedule_action(package, SCRIPT_INSTALL, L"MsiPublishAssemblies"); 601 602 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) 603 { 604 LONG res; 605 HKEY hkey; 606 GUID guid; 607 DWORD size; 608 WCHAR buffer[43]; 609 MSIRECORD *uirow; 610 MSIASSEMBLY *assembly = comp->assembly; 611 BOOL win32; 612 613 if (!assembly || !comp->ComponentId) continue; 614 615 comp->Action = msi_get_component_action( package, comp ); 616 if (comp->Action != INSTALLSTATE_LOCAL) 617 { 618 TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component)); 619 continue; 620 } 621 TRACE("publishing %s\n", debugstr_w(comp->Component)); 622 623 CLSIDFromString( package->ProductCode, &guid ); 624 encode_base85_guid( &guid, buffer ); 625 buffer[20] = '>'; 626 CLSIDFromString( comp->ComponentId, &guid ); 627 encode_base85_guid( &guid, buffer + 21 ); 628 buffer[42] = 0; 629 630 win32 = assembly->attributes & msidbAssemblyAttributesWin32; 631 if (assembly->application) 632 { 633 MSIFILE *file = msi_get_loaded_file( package, assembly->application ); 634 if (!file) 635 { 636 WARN("no matching file %s for local assembly\n", debugstr_w(assembly->application)); 637 continue; 638 } 639 if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey ))) 640 { 641 WARN( "failed to open local assembly key %ld\n", res ); 642 return ERROR_FUNCTION_FAILED; 643 } 644 } 645 else 646 { 647 if ((res = open_global_assembly_key( package->Context, win32, &hkey ))) 648 { 649 WARN( "failed to open global assembly key %ld\n", res ); 650 return ERROR_FUNCTION_FAILED; 651 } 652 } 653 size = sizeof(buffer); 654 if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size ))) 655 { 656 WARN( "failed to set assembly value %ld\n", res ); 657 } 658 RegCloseKey( hkey ); 659 660 uirow = MSI_CreateRecord( 2 ); 661 MSI_RecordSetStringW( uirow, 2, assembly->display_name ); 662 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 663 msiobj_release( &uirow->hdr ); 664 } 665 return ERROR_SUCCESS; 666 } 667 668 UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package ) 669 { 670 MSICOMPONENT *comp; 671 672 if (package->script == SCRIPT_NONE) 673 return msi_schedule_action(package, SCRIPT_INSTALL, L"MsiUnpublishAssemblies"); 674 675 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) 676 { 677 LONG res; 678 MSIRECORD *uirow; 679 MSIASSEMBLY *assembly = comp->assembly; 680 BOOL win32; 681 682 if (!assembly || !comp->ComponentId) continue; 683 684 comp->Action = msi_get_component_action( package, comp ); 685 if (comp->Action != INSTALLSTATE_ABSENT) 686 { 687 TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component)); 688 continue; 689 } 690 TRACE("unpublishing %s\n", debugstr_w(comp->Component)); 691 692 win32 = assembly->attributes & msidbAssemblyAttributesWin32; 693 if (assembly->application) 694 { 695 MSIFILE *file = msi_get_loaded_file( package, assembly->application ); 696 if (!file) 697 { 698 WARN("no matching file %s for local assembly\n", debugstr_w(assembly->application)); 699 continue; 700 } 701 if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath ))) 702 WARN( "failed to delete local assembly key %ld\n", res ); 703 } 704 else 705 { 706 HKEY hkey; 707 if ((res = open_global_assembly_key( package->Context, win32, &hkey ))) 708 WARN( "failed to delete global assembly key %ld\n", res ); 709 else 710 { 711 if ((res = RegDeleteValueW( hkey, assembly->display_name ))) 712 WARN( "failed to delete global assembly value %ld\n", res ); 713 RegCloseKey( hkey ); 714 } 715 } 716 717 uirow = MSI_CreateRecord( 2 ); 718 MSI_RecordSetStringW( uirow, 2, assembly->display_name ); 719 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 720 msiobj_release( &uirow->hdr ); 721 } 722 return ERROR_SUCCESS; 723 } 724