1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 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 /* Actions handled in this module: 22 * 23 * RegisterClassInfo 24 * RegisterProgIdInfo 25 * RegisterExtensionInfo 26 * RegisterMIMEInfo 27 * UnregisterClassInfo 28 * UnregisterProgIdInfo 29 * UnregisterExtensionInfo 30 * UnregisterMIMEInfo 31 */ 32 33 #include "msipriv.h" 34 35 WINE_DEFAULT_DEBUG_CHANNEL(msi); 36 37 static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row ) 38 { 39 LPCWSTR buffer; 40 MSIAPPID *appid; 41 42 /* fill in the data */ 43 44 appid = msi_alloc_zero( sizeof(MSIAPPID) ); 45 if (!appid) 46 return NULL; 47 48 appid->AppID = msi_dup_record_field( row, 1 ); 49 TRACE("loading appid %s\n", debugstr_w( appid->AppID )); 50 51 buffer = MSI_RecordGetString(row,2); 52 deformat_string( package, buffer, &appid->RemoteServerName ); 53 54 appid->LocalServer = msi_dup_record_field(row,3); 55 appid->ServiceParameters = msi_dup_record_field(row,4); 56 appid->DllSurrogate = msi_dup_record_field(row,5); 57 58 appid->ActivateAtStorage = !MSI_RecordIsNull(row,6); 59 appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7); 60 61 list_add_tail( &package->appids, &appid->entry ); 62 63 return appid; 64 } 65 66 static MSIAPPID *load_given_appid( MSIPACKAGE *package, LPCWSTR name ) 67 { 68 static const WCHAR query[] = { 69 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 70 '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ', 71 '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0}; 72 MSIRECORD *row; 73 MSIAPPID *appid; 74 75 if (!name) 76 return NULL; 77 78 /* check for appids already loaded */ 79 LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry ) 80 { 81 if (!strcmpiW( appid->AppID, name )) 82 { 83 TRACE("found appid %s %p\n", debugstr_w(name), appid); 84 return appid; 85 } 86 } 87 88 row = MSI_QueryGetRecord(package->db, query, name); 89 if (!row) 90 return NULL; 91 92 appid = load_appid(package, row); 93 msiobj_release(&row->hdr); 94 return appid; 95 } 96 97 static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR progid); 98 static MSICLASS *load_given_class( MSIPACKAGE *package, LPCWSTR classid ); 99 100 static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row ) 101 { 102 MSIPROGID *progid; 103 LPCWSTR buffer; 104 105 /* fill in the data */ 106 107 progid = msi_alloc_zero( sizeof(MSIPROGID) ); 108 if (!progid) 109 return NULL; 110 111 list_add_tail( &package->progids, &progid->entry ); 112 113 progid->ProgID = msi_dup_record_field(row,1); 114 TRACE("loading progid %s\n",debugstr_w(progid->ProgID)); 115 116 buffer = MSI_RecordGetString(row,2); 117 progid->Parent = load_given_progid(package,buffer); 118 if (progid->Parent == NULL && buffer) 119 FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer)); 120 121 buffer = MSI_RecordGetString(row,3); 122 progid->Class = load_given_class(package,buffer); 123 if (progid->Class == NULL && buffer) 124 FIXME("Unknown class %s\n",debugstr_w(buffer)); 125 126 progid->Description = msi_dup_record_field(row,4); 127 128 if (!MSI_RecordIsNull(row,6)) 129 { 130 INT icon_index = MSI_RecordGetInteger(row,6); 131 LPCWSTR FileName = MSI_RecordGetString(row,5); 132 LPWSTR FilePath; 133 static const WCHAR fmt[] = {'%','s',',','%','i',0}; 134 135 FilePath = msi_build_icon_path(package, FileName); 136 137 progid->IconPath = msi_alloc( (strlenW(FilePath)+10)* sizeof(WCHAR) ); 138 139 sprintfW(progid->IconPath,fmt,FilePath,icon_index); 140 141 msi_free(FilePath); 142 } 143 else 144 { 145 buffer = MSI_RecordGetString(row,5); 146 if (buffer) 147 progid->IconPath = msi_build_icon_path(package, buffer); 148 } 149 150 progid->CurVer = NULL; 151 progid->VersionInd = NULL; 152 153 /* if we have a parent then we may be that parents CurVer */ 154 if (progid->Parent && progid->Parent != progid) 155 { 156 MSIPROGID *parent = progid->Parent; 157 158 while (parent->Parent && parent->Parent != parent) 159 parent = parent->Parent; 160 161 /* FIXME: need to determine if we are really the CurVer */ 162 163 progid->CurVer = parent; 164 parent->VersionInd = progid; 165 } 166 167 return progid; 168 } 169 170 static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR name) 171 { 172 static const WCHAR query[] = { 173 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 174 '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ', 175 '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0}; 176 MSIPROGID *progid; 177 MSIRECORD *row; 178 179 if (!name) 180 return NULL; 181 182 /* check for progids already loaded */ 183 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) 184 { 185 if (!strcmpiW( progid->ProgID, name )) 186 { 187 TRACE("found progid %s (%p)\n",debugstr_w(name), progid ); 188 return progid; 189 } 190 } 191 192 row = MSI_QueryGetRecord( package->db, query, name ); 193 if (!row) 194 return NULL; 195 196 progid = load_progid(package, row); 197 msiobj_release(&row->hdr); 198 return progid; 199 } 200 201 static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row ) 202 { 203 MSICLASS *cls; 204 DWORD i; 205 LPCWSTR buffer; 206 207 /* fill in the data */ 208 209 cls = msi_alloc_zero( sizeof(MSICLASS) ); 210 if (!cls) 211 return NULL; 212 213 list_add_tail( &package->classes, &cls->entry ); 214 215 cls->clsid = msi_dup_record_field( row, 1 ); 216 TRACE("loading class %s\n",debugstr_w(cls->clsid)); 217 cls->Context = msi_dup_record_field( row, 2 ); 218 buffer = MSI_RecordGetString(row,3); 219 cls->Component = msi_get_loaded_component( package, buffer ); 220 221 cls->ProgIDText = msi_dup_record_field(row,4); 222 cls->ProgID = load_given_progid(package, cls->ProgIDText); 223 224 cls->Description = msi_dup_record_field(row,5); 225 226 buffer = MSI_RecordGetString(row,6); 227 if (buffer) 228 cls->AppID = load_given_appid(package, buffer); 229 230 cls->FileTypeMask = msi_dup_record_field(row,7); 231 232 if (!MSI_RecordIsNull(row,9)) 233 { 234 235 INT icon_index = MSI_RecordGetInteger(row,9); 236 LPCWSTR FileName = MSI_RecordGetString(row,8); 237 LPWSTR FilePath; 238 static const WCHAR fmt[] = {'%','s',',','%','i',0}; 239 240 FilePath = msi_build_icon_path(package, FileName); 241 242 cls->IconPath = msi_alloc( (strlenW(FilePath)+5)* sizeof(WCHAR) ); 243 244 sprintfW(cls->IconPath,fmt,FilePath,icon_index); 245 246 msi_free(FilePath); 247 } 248 else 249 { 250 buffer = MSI_RecordGetString(row,8); 251 if (buffer) 252 cls->IconPath = msi_build_icon_path(package, buffer); 253 } 254 255 if (!MSI_RecordIsNull(row,10)) 256 { 257 i = MSI_RecordGetInteger(row,10); 258 if (i != MSI_NULL_INTEGER && i > 0 && i < 4) 259 { 260 static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0}; 261 static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0}; 262 263 switch(i) 264 { 265 case 1: 266 cls->DefInprocHandler = strdupW(ole2); 267 break; 268 case 2: 269 cls->DefInprocHandler32 = strdupW(ole32); 270 break; 271 case 3: 272 cls->DefInprocHandler = strdupW(ole2); 273 cls->DefInprocHandler32 = strdupW(ole32); 274 break; 275 } 276 } 277 else 278 { 279 cls->DefInprocHandler32 = msi_dup_record_field( row, 10 ); 280 msi_reduce_to_long_filename( cls->DefInprocHandler32 ); 281 } 282 } 283 buffer = MSI_RecordGetString(row,11); 284 deformat_string(package,buffer,&cls->Argument); 285 286 buffer = MSI_RecordGetString(row,12); 287 cls->Feature = msi_get_loaded_feature(package, buffer); 288 289 cls->Attributes = MSI_RecordGetInteger(row,13); 290 291 return cls; 292 } 293 294 /* 295 * the Class table has 3 primary keys. Generally it is only 296 * referenced through the first CLSID key. However when loading 297 * all of the classes we need to make sure we do not ignore rows 298 * with other Context and ComponentIndexs 299 */ 300 static MSICLASS *load_given_class(MSIPACKAGE *package, LPCWSTR classid) 301 { 302 static const WCHAR query[] = { 303 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 304 '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ', 305 '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0}; 306 MSICLASS *cls; 307 MSIRECORD *row; 308 309 if (!classid) 310 return NULL; 311 312 /* check for classes already loaded */ 313 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) 314 { 315 if (!strcmpiW( cls->clsid, classid )) 316 { 317 TRACE("found class %s (%p)\n",debugstr_w(classid), cls); 318 return cls; 319 } 320 } 321 322 row = MSI_QueryGetRecord(package->db, query, classid); 323 if (!row) 324 return NULL; 325 326 cls = load_class(package, row); 327 msiobj_release(&row->hdr); 328 return cls; 329 } 330 331 static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR extension ); 332 333 static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row ) 334 { 335 LPCWSTR extension; 336 MSIMIME *mt; 337 338 /* fill in the data */ 339 340 mt = msi_alloc_zero( sizeof(MSIMIME) ); 341 if (!mt) 342 return mt; 343 344 mt->ContentType = msi_dup_record_field( row, 1 ); 345 TRACE("loading mime %s\n", debugstr_w(mt->ContentType)); 346 347 extension = MSI_RecordGetString( row, 2 ); 348 mt->Extension = load_given_extension( package, extension ); 349 mt->suffix = strdupW( extension ); 350 351 mt->clsid = msi_dup_record_field( row, 3 ); 352 mt->Class = load_given_class( package, mt->clsid ); 353 354 list_add_tail( &package->mimes, &mt->entry ); 355 356 return mt; 357 } 358 359 static MSIMIME *load_given_mime( MSIPACKAGE *package, LPCWSTR mime ) 360 { 361 static const WCHAR query[] = { 362 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 363 '`','M','I','M','E','`',' ','W','H','E','R','E',' ', 364 '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ','\'','%','s','\'',0}; 365 MSIRECORD *row; 366 MSIMIME *mt; 367 368 if (!mime) 369 return NULL; 370 371 /* check for mime already loaded */ 372 LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry ) 373 { 374 if (!strcmpiW( mt->ContentType, mime )) 375 { 376 TRACE("found mime %s (%p)\n",debugstr_w(mime), mt); 377 return mt; 378 } 379 } 380 381 row = MSI_QueryGetRecord(package->db, query, mime); 382 if (!row) 383 return NULL; 384 385 mt = load_mime(package, row); 386 msiobj_release(&row->hdr); 387 return mt; 388 } 389 390 static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row ) 391 { 392 MSIEXTENSION *ext; 393 LPCWSTR buffer; 394 395 /* fill in the data */ 396 397 ext = msi_alloc_zero( sizeof(MSIEXTENSION) ); 398 if (!ext) 399 return NULL; 400 401 list_init( &ext->verbs ); 402 403 list_add_tail( &package->extensions, &ext->entry ); 404 405 ext->Extension = msi_dup_record_field( row, 1 ); 406 TRACE("loading extension %s\n", debugstr_w(ext->Extension)); 407 408 buffer = MSI_RecordGetString( row, 2 ); 409 ext->Component = msi_get_loaded_component( package, buffer ); 410 411 ext->ProgIDText = msi_dup_record_field( row, 3 ); 412 ext->ProgID = load_given_progid( package, ext->ProgIDText ); 413 414 buffer = MSI_RecordGetString( row, 4 ); 415 ext->Mime = load_given_mime( package, buffer ); 416 417 buffer = MSI_RecordGetString(row,5); 418 ext->Feature = msi_get_loaded_feature( package, buffer ); 419 420 return ext; 421 } 422 423 /* 424 * While the extension table has 2 primary keys, this function is only looking 425 * at the Extension key which is what is referenced as a foreign key 426 */ 427 static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR name ) 428 { 429 static const WCHAR query[] = { 430 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 431 '`','E','x','t','e','n','s','i','o','n','`',' ','W','H','E','R','E',' ', 432 '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ','\'','%','s','\'',0}; 433 MSIEXTENSION *ext; 434 MSIRECORD *row; 435 436 if (!name) 437 return NULL; 438 439 if (name[0] == '.') 440 name++; 441 442 /* check for extensions already loaded */ 443 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) 444 { 445 if (!strcmpiW( ext->Extension, name )) 446 { 447 TRACE("extension %s already loaded %p\n", debugstr_w(name), ext); 448 return ext; 449 } 450 } 451 452 row = MSI_QueryGetRecord( package->db, query, name ); 453 if (!row) 454 return NULL; 455 456 ext = load_extension(package, row); 457 msiobj_release(&row->hdr); 458 return ext; 459 } 460 461 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param) 462 { 463 MSIPACKAGE* package = param; 464 MSIVERB *verb; 465 LPCWSTR buffer; 466 MSIEXTENSION *extension; 467 468 buffer = MSI_RecordGetString(row,1); 469 extension = load_given_extension( package, buffer ); 470 if (!extension) 471 { 472 ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer)); 473 return ERROR_SUCCESS; 474 } 475 476 /* fill in the data */ 477 478 verb = msi_alloc_zero( sizeof(MSIVERB) ); 479 if (!verb) 480 return ERROR_OUTOFMEMORY; 481 482 verb->Verb = msi_dup_record_field(row,2); 483 TRACE("loading verb %s\n",debugstr_w(verb->Verb)); 484 verb->Sequence = MSI_RecordGetInteger(row,3); 485 486 buffer = MSI_RecordGetString(row,4); 487 deformat_string(package,buffer,&verb->Command); 488 489 buffer = MSI_RecordGetString(row,5); 490 deformat_string(package,buffer,&verb->Argument); 491 492 /* associate the verb with the correct extension */ 493 list_add_tail( &extension->verbs, &verb->entry ); 494 495 return ERROR_SUCCESS; 496 } 497 498 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param) 499 { 500 MSICOMPONENT *comp; 501 LPCWSTR clsid; 502 LPCWSTR context; 503 LPCWSTR buffer; 504 MSIPACKAGE* package = param; 505 MSICLASS *cls; 506 BOOL match = FALSE; 507 508 clsid = MSI_RecordGetString(rec,1); 509 context = MSI_RecordGetString(rec,2); 510 buffer = MSI_RecordGetString(rec,3); 511 comp = msi_get_loaded_component(package, buffer); 512 513 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) 514 { 515 if (strcmpiW( clsid, cls->clsid )) 516 continue; 517 if (strcmpW( context, cls->Context )) 518 continue; 519 if (comp == cls->Component) 520 { 521 match = TRUE; 522 break; 523 } 524 } 525 526 if (!match) 527 load_class(package, rec); 528 529 return ERROR_SUCCESS; 530 } 531 532 static UINT load_all_classes( MSIPACKAGE *package ) 533 { 534 static const WCHAR query[] = { 535 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','C','l','a','s','s','`',0}; 536 MSIQUERY *view; 537 UINT rc; 538 539 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 540 if (rc != ERROR_SUCCESS) 541 return ERROR_SUCCESS; 542 543 rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package); 544 msiobj_release(&view->hdr); 545 return rc; 546 } 547 548 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param) 549 { 550 MSICOMPONENT *comp; 551 LPCWSTR buffer; 552 LPCWSTR extension; 553 MSIPACKAGE* package = param; 554 BOOL match = FALSE; 555 MSIEXTENSION *ext; 556 557 extension = MSI_RecordGetString(rec,1); 558 buffer = MSI_RecordGetString(rec,2); 559 comp = msi_get_loaded_component(package, buffer); 560 561 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) 562 { 563 if (strcmpiW(extension, ext->Extension)) 564 continue; 565 if (comp == ext->Component) 566 { 567 match = TRUE; 568 break; 569 } 570 } 571 572 if (!match) 573 load_extension(package, rec); 574 575 return ERROR_SUCCESS; 576 } 577 578 static UINT load_all_extensions( MSIPACKAGE *package ) 579 { 580 static const WCHAR query[] = { 581 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','E','x','t','e','n','s','i','o','n','`',0}; 582 MSIQUERY *view; 583 UINT rc; 584 585 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 586 if (rc != ERROR_SUCCESS) 587 return ERROR_SUCCESS; 588 589 rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package); 590 msiobj_release(&view->hdr); 591 return rc; 592 } 593 594 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param) 595 { 596 LPCWSTR buffer; 597 MSIPACKAGE* package = param; 598 599 buffer = MSI_RecordGetString(rec,1); 600 load_given_progid(package,buffer); 601 return ERROR_SUCCESS; 602 } 603 604 static UINT load_all_progids( MSIPACKAGE *package ) 605 { 606 static const WCHAR query[] = { 607 'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ','F','R','O','M',' ', 608 '`','P','r','o','g','I','d','`',0}; 609 MSIQUERY *view; 610 UINT rc; 611 612 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 613 if (rc != ERROR_SUCCESS) 614 return ERROR_SUCCESS; 615 616 rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package); 617 msiobj_release(&view->hdr); 618 return rc; 619 } 620 621 static UINT load_all_verbs( MSIPACKAGE *package ) 622 { 623 static const WCHAR query[] = { 624 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','V','e','r','b','`',0}; 625 MSIQUERY *view; 626 UINT rc; 627 628 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 629 if (rc != ERROR_SUCCESS) 630 return ERROR_SUCCESS; 631 632 rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package); 633 msiobj_release(&view->hdr); 634 return rc; 635 } 636 637 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param) 638 { 639 LPCWSTR buffer; 640 MSIPACKAGE* package = param; 641 642 buffer = MSI_RecordGetString(rec,1); 643 load_given_mime(package,buffer); 644 return ERROR_SUCCESS; 645 } 646 647 static UINT load_all_mimes( MSIPACKAGE *package ) 648 { 649 static const WCHAR query[] = { 650 'S','E','L','E','C','T',' ','`','C','o','n','t','e','n','t','T','y','p','e','`',' ', 651 'F','R','O','M',' ','`','M','I','M','E','`',0}; 652 MSIQUERY *view; 653 UINT rc; 654 655 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 656 if (rc != ERROR_SUCCESS) 657 return ERROR_SUCCESS; 658 659 rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package); 660 msiobj_release(&view->hdr); 661 return rc; 662 } 663 664 static UINT load_classes_and_such( MSIPACKAGE *package ) 665 { 666 UINT r; 667 668 TRACE("Loading all the class info and related tables\n"); 669 670 /* check if already loaded */ 671 if (!list_empty( &package->classes ) || 672 !list_empty( &package->mimes ) || 673 !list_empty( &package->extensions ) || 674 !list_empty( &package->progids )) return ERROR_SUCCESS; 675 676 r = load_all_classes( package ); 677 if (r != ERROR_SUCCESS) return r; 678 679 r = load_all_extensions( package ); 680 if (r != ERROR_SUCCESS) return r; 681 682 r = load_all_progids( package ); 683 if (r != ERROR_SUCCESS) return r; 684 685 /* these loads must come after the other loads */ 686 r = load_all_verbs( package ); 687 if (r != ERROR_SUCCESS) return r; 688 689 return load_all_mimes( package ); 690 } 691 692 static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid ) 693 { 694 MSIPROGID *child; 695 696 if (!progid) 697 return; 698 699 if (progid->InstallMe) 700 return; 701 702 progid->InstallMe = TRUE; 703 704 /* all children if this is a parent also install */ 705 LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry ) 706 { 707 if (child->Parent == progid) 708 mark_progid_for_install( package, child ); 709 } 710 } 711 712 static void mark_progid_for_uninstall( MSIPACKAGE *package, MSIPROGID *progid ) 713 { 714 MSIPROGID *child; 715 716 if (!progid) 717 return; 718 719 if (!progid->InstallMe) 720 return; 721 722 progid->InstallMe = FALSE; 723 724 LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry ) 725 { 726 if (child->Parent == progid) 727 mark_progid_for_uninstall( package, child ); 728 } 729 } 730 731 static void mark_mime_for_install( MSIMIME *mime ) 732 { 733 if (!mime) 734 return; 735 mime->InstallMe = TRUE; 736 } 737 738 static void mark_mime_for_uninstall( MSIMIME *mime ) 739 { 740 if (!mime) 741 return; 742 mime->InstallMe = FALSE; 743 } 744 745 static UINT register_appid(const MSIAPPID *appid, LPCWSTR app ) 746 { 747 static const WCHAR szRemoteServerName[] = 748 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0}; 749 static const WCHAR szLocalService[] = 750 {'L','o','c','a','l','S','e','r','v','i','c','e',0}; 751 static const WCHAR szService[] = 752 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0}; 753 static const WCHAR szDLL[] = 754 {'D','l','l','S','u','r','r','o','g','a','t','e',0}; 755 static const WCHAR szActivate[] = 756 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0}; 757 static const WCHAR szY[] = {'Y',0}; 758 static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; 759 static const WCHAR szUser[] = 760 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0}; 761 762 HKEY hkey2,hkey3; 763 764 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); 765 RegCreateKeyW( hkey2, appid->AppID, &hkey3 ); 766 RegCloseKey(hkey2); 767 msi_reg_set_val_str( hkey3, NULL, app ); 768 769 if (appid->RemoteServerName) 770 msi_reg_set_val_str( hkey3, szRemoteServerName, appid->RemoteServerName ); 771 772 if (appid->LocalServer) 773 msi_reg_set_val_str( hkey3, szLocalService, appid->LocalServer ); 774 775 if (appid->ServiceParameters) 776 msi_reg_set_val_str( hkey3, szService, appid->ServiceParameters ); 777 778 if (appid->DllSurrogate) 779 msi_reg_set_val_str( hkey3, szDLL, appid->DllSurrogate ); 780 781 if (appid->ActivateAtStorage) 782 msi_reg_set_val_str( hkey3, szActivate, szY ); 783 784 if (appid->RunAsInteractiveUser) 785 msi_reg_set_val_str( hkey3, szRunAs, szUser ); 786 787 RegCloseKey(hkey3); 788 return ERROR_SUCCESS; 789 } 790 791 UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) 792 { 793 static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0}; 794 const WCHAR *keypath; 795 MSIRECORD *uirow; 796 HKEY hkey, hkey2, hkey3; 797 MSICLASS *cls; 798 UINT r; 799 800 r = load_classes_and_such( package ); 801 if (r != ERROR_SUCCESS) 802 return r; 803 804 if (is_64bit && package->platform == PLATFORM_INTEL) 805 keypath = szWow6432NodeCLSID; 806 else 807 keypath = szCLSID; 808 809 if (RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, &hkey) != ERROR_SUCCESS) 810 return ERROR_FUNCTION_FAILED; 811 812 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) 813 { 814 MSICOMPONENT *comp; 815 MSIFILE *file; 816 DWORD size; 817 LPWSTR argument; 818 MSIFEATURE *feature; 819 820 comp = cls->Component; 821 if ( !comp ) 822 continue; 823 824 if (!comp->Enabled) 825 { 826 TRACE("component is disabled\n"); 827 continue; 828 } 829 830 feature = cls->Feature; 831 if (!feature) 832 continue; 833 834 feature->Action = msi_get_feature_action( package, feature ); 835 if (feature->Action != INSTALLSTATE_LOCAL && 836 feature->Action != INSTALLSTATE_ADVERTISED ) 837 { 838 TRACE("feature %s not scheduled for installation, skipping registration of class %s\n", 839 debugstr_w(feature->Feature), debugstr_w(cls->clsid)); 840 continue; 841 } 842 843 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath ))) 844 { 845 TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid)); 846 continue; 847 } 848 TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls); 849 850 cls->Installed = TRUE; 851 mark_progid_for_install( package, cls->ProgID ); 852 853 RegCreateKeyW( hkey, cls->clsid, &hkey2 ); 854 855 if (cls->Description) 856 msi_reg_set_val_str( hkey2, NULL, cls->Description ); 857 858 RegCreateKeyW( hkey2, cls->Context, &hkey3 ); 859 860 /* 861 * FIXME: Implement install on demand (advertised components). 862 * 863 * ole32.dll should call msi.MsiProvideComponentFromDescriptor() 864 * when it needs an InProcServer that doesn't exist. 865 * The component advertise string should be in the "InProcServer" value. 866 */ 867 size = lstrlenW( file->TargetPath )+1; 868 if (cls->Argument) 869 size += lstrlenW(cls->Argument)+1; 870 871 argument = msi_alloc( size * sizeof(WCHAR) ); 872 lstrcpyW( argument, file->TargetPath ); 873 874 if (cls->Argument) 875 { 876 lstrcatW( argument, szSpace ); 877 lstrcatW( argument, cls->Argument ); 878 } 879 880 msi_reg_set_val_str( hkey3, NULL, argument ); 881 msi_free(argument); 882 883 RegCloseKey(hkey3); 884 885 if (cls->ProgID || cls->ProgIDText) 886 { 887 LPCWSTR progid; 888 889 if (cls->ProgID) 890 progid = cls->ProgID->ProgID; 891 else 892 progid = cls->ProgIDText; 893 894 msi_reg_set_subkey_val( hkey2, szProgID, NULL, progid ); 895 896 if (cls->ProgID && cls->ProgID->VersionInd) 897 { 898 msi_reg_set_subkey_val( hkey2, szVIProgID, NULL, 899 cls->ProgID->VersionInd->ProgID ); 900 } 901 } 902 903 if (cls->AppID) 904 { 905 MSIAPPID *appid = cls->AppID; 906 msi_reg_set_val_str( hkey2, szAppID, appid->AppID ); 907 register_appid( appid, cls->Description ); 908 } 909 910 if (cls->IconPath) 911 msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath ); 912 913 if (cls->DefInprocHandler) 914 msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler ); 915 916 if (cls->DefInprocHandler32) 917 msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 ); 918 919 RegCloseKey(hkey2); 920 921 /* if there is a FileTypeMask, register the FileType */ 922 if (cls->FileTypeMask) 923 { 924 LPWSTR ptr, ptr2; 925 LPWSTR keyname; 926 INT index = 0; 927 ptr = cls->FileTypeMask; 928 while (ptr && *ptr) 929 { 930 ptr2 = strchrW(ptr,';'); 931 if (ptr2) 932 *ptr2 = 0; 933 keyname = msi_alloc( (strlenW(szFileType_fmt) + strlenW(cls->clsid) + 4) * sizeof(WCHAR)); 934 sprintfW( keyname, szFileType_fmt, cls->clsid, index ); 935 936 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, ptr ); 937 msi_free(keyname); 938 939 if (ptr2) 940 ptr = ptr2+1; 941 else 942 ptr = NULL; 943 944 index ++; 945 } 946 } 947 948 uirow = MSI_CreateRecord(1); 949 MSI_RecordSetStringW( uirow, 1, cls->clsid ); 950 msi_ui_actiondata( package, szRegisterClassInfo, uirow ); 951 msiobj_release(&uirow->hdr); 952 } 953 RegCloseKey(hkey); 954 return ERROR_SUCCESS; 955 } 956 957 UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package ) 958 { 959 static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0}; 960 const WCHAR *keypath; 961 MSIRECORD *uirow; 962 MSICLASS *cls; 963 HKEY hkey, hkey2; 964 UINT r; 965 966 r = load_classes_and_such( package ); 967 if (r != ERROR_SUCCESS) 968 return r; 969 970 if (is_64bit && package->platform == PLATFORM_INTEL) 971 keypath = szWow6432NodeCLSID; 972 else 973 keypath = szCLSID; 974 975 if (RegOpenKeyW( HKEY_CLASSES_ROOT, keypath, &hkey ) != ERROR_SUCCESS) 976 return ERROR_SUCCESS; 977 978 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) 979 { 980 MSIFEATURE *feature; 981 MSICOMPONENT *comp; 982 LPWSTR filetype; 983 LONG res; 984 985 comp = cls->Component; 986 if (!comp) 987 continue; 988 989 if (!comp->Enabled) 990 { 991 TRACE("component is disabled\n"); 992 continue; 993 } 994 995 feature = cls->Feature; 996 if (!feature) 997 continue; 998 999 feature->Action = msi_get_feature_action( package, feature ); 1000 if (feature->Action != INSTALLSTATE_ABSENT) 1001 { 1002 TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n", 1003 debugstr_w(feature->Feature), debugstr_w(cls->clsid)); 1004 continue; 1005 } 1006 TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls); 1007 1008 cls->Installed = FALSE; 1009 mark_progid_for_uninstall( package, cls->ProgID ); 1010 1011 res = RegDeleteTreeW( hkey, cls->clsid ); 1012 if (res != ERROR_SUCCESS) 1013 WARN("Failed to delete class key %d\n", res); 1014 1015 if (cls->AppID) 1016 { 1017 res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 ); 1018 if (res == ERROR_SUCCESS) 1019 { 1020 res = RegDeleteKeyW( hkey2, cls->AppID->AppID ); 1021 if (res != ERROR_SUCCESS) 1022 WARN("Failed to delete appid key %d\n", res); 1023 RegCloseKey( hkey2 ); 1024 } 1025 } 1026 if (cls->FileTypeMask) 1027 { 1028 filetype = msi_alloc( (strlenW( szFileType ) + strlenW( cls->clsid ) + 1) * sizeof(WCHAR) ); 1029 if (filetype) 1030 { 1031 strcpyW( filetype, szFileType ); 1032 strcatW( filetype, cls->clsid ); 1033 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype ); 1034 msi_free( filetype ); 1035 1036 if (res != ERROR_SUCCESS) 1037 WARN("Failed to delete file type %d\n", res); 1038 } 1039 } 1040 1041 uirow = MSI_CreateRecord( 1 ); 1042 MSI_RecordSetStringW( uirow, 1, cls->clsid ); 1043 msi_ui_actiondata( package, szUnregisterClassInfo, uirow ); 1044 msiobj_release( &uirow->hdr ); 1045 } 1046 RegCloseKey( hkey ); 1047 return ERROR_SUCCESS; 1048 } 1049 1050 static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid ) 1051 { 1052 while (progid) 1053 { 1054 if (progid->Class) 1055 return progid->Class->clsid; 1056 if (progid->Parent == progid) 1057 break; 1058 progid = progid->Parent; 1059 } 1060 return NULL; 1061 } 1062 1063 static UINT register_progid( const MSIPROGID* progid ) 1064 { 1065 static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0}; 1066 HKEY hkey = 0; 1067 UINT rc; 1068 1069 rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey ); 1070 if (rc == ERROR_SUCCESS) 1071 { 1072 LPCWSTR clsid = get_clsid_of_progid( progid ); 1073 1074 if (clsid) 1075 msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid ); 1076 else 1077 TRACE("%s has no class\n", debugstr_w( progid->ProgID ) ); 1078 1079 if (progid->Description) 1080 msi_reg_set_val_str( hkey, NULL, progid->Description ); 1081 1082 if (progid->IconPath) 1083 msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath ); 1084 1085 /* write out the current version */ 1086 if (progid->CurVer) 1087 msi_reg_set_subkey_val( hkey, szCurVer, NULL, progid->CurVer->ProgID ); 1088 1089 RegCloseKey(hkey); 1090 } 1091 else 1092 ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) ); 1093 1094 return rc; 1095 } 1096 1097 UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) 1098 { 1099 MSIPROGID *progid; 1100 MSIRECORD *uirow; 1101 UINT r; 1102 1103 r = load_classes_and_such( package ); 1104 if (r != ERROR_SUCCESS) 1105 return r; 1106 1107 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) 1108 { 1109 /* check if this progid is to be installed */ 1110 if (progid->Class && progid->Class->Installed) 1111 progid->InstallMe = TRUE; 1112 1113 if (!progid->InstallMe) 1114 { 1115 TRACE("progid %s not scheduled to be installed\n", 1116 debugstr_w(progid->ProgID)); 1117 continue; 1118 } 1119 1120 TRACE("Registering progid %s\n", debugstr_w(progid->ProgID)); 1121 1122 register_progid( progid ); 1123 1124 uirow = MSI_CreateRecord( 1 ); 1125 MSI_RecordSetStringW( uirow, 1, progid->ProgID ); 1126 msi_ui_actiondata( package, szRegisterProgIdInfo, uirow ); 1127 msiobj_release( &uirow->hdr ); 1128 } 1129 return ERROR_SUCCESS; 1130 } 1131 1132 UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package ) 1133 { 1134 MSIPROGID *progid; 1135 MSIRECORD *uirow; 1136 LONG res; 1137 UINT r; 1138 1139 r = load_classes_and_such( package ); 1140 if (r != ERROR_SUCCESS) 1141 return r; 1142 1143 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) 1144 { 1145 /* check if this progid is to be removed */ 1146 if (progid->Class && !progid->Class->Installed) 1147 progid->InstallMe = FALSE; 1148 1149 if (progid->InstallMe) 1150 { 1151 TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID)); 1152 continue; 1153 } 1154 1155 TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID)); 1156 1157 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID ); 1158 if (res != ERROR_SUCCESS) 1159 TRACE("Failed to delete progid key %d\n", res); 1160 1161 uirow = MSI_CreateRecord( 1 ); 1162 MSI_RecordSetStringW( uirow, 1, progid->ProgID ); 1163 msi_ui_actiondata( package, szUnregisterProgIdInfo, uirow ); 1164 msiobj_release( &uirow->hdr ); 1165 } 1166 return ERROR_SUCCESS; 1167 } 1168 1169 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 1170 MSICOMPONENT* component, const MSIEXTENSION* extension, 1171 MSIVERB* verb, INT* Sequence ) 1172 { 1173 LPWSTR keyname; 1174 HKEY key; 1175 static const WCHAR szShell[] = {'s','h','e','l','l',0}; 1176 static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0}; 1177 static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0}; 1178 static const WCHAR fmt2[] = {'\"','%','s','\"',0}; 1179 LPWSTR command; 1180 DWORD size; 1181 LPWSTR advertise; 1182 1183 keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand); 1184 1185 TRACE("Making Key %s\n",debugstr_w(keyname)); 1186 RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); 1187 size = strlenW(component->FullKeypath); 1188 if (verb->Argument) 1189 size += strlenW(verb->Argument); 1190 size += 4; 1191 1192 command = msi_alloc(size * sizeof (WCHAR)); 1193 if (verb->Argument) 1194 sprintfW(command, fmt, component->FullKeypath, verb->Argument); 1195 else 1196 sprintfW(command, fmt2, component->FullKeypath); 1197 1198 msi_reg_set_val_str( key, NULL, command ); 1199 msi_free(command); 1200 1201 advertise = msi_create_component_advertise_string(package, component, 1202 extension->Feature->Feature); 1203 size = strlenW(advertise); 1204 1205 if (verb->Argument) 1206 size += strlenW(verb->Argument); 1207 size += 4; 1208 1209 command = msi_alloc_zero(size * sizeof (WCHAR)); 1210 1211 strcpyW(command,advertise); 1212 if (verb->Argument) 1213 { 1214 strcatW(command,szSpace); 1215 strcatW(command,verb->Argument); 1216 } 1217 1218 msi_reg_set_val_multi_str( key, szCommand, command ); 1219 1220 RegCloseKey(key); 1221 msi_free(keyname); 1222 msi_free(advertise); 1223 msi_free(command); 1224 1225 if (verb->Command) 1226 { 1227 keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb ); 1228 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command ); 1229 msi_free(keyname); 1230 } 1231 1232 if (verb->Sequence != MSI_NULL_INTEGER) 1233 { 1234 if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence) 1235 { 1236 *Sequence = verb->Sequence; 1237 keyname = msi_build_directory_name( 2, progid, szShell ); 1238 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb ); 1239 msi_free(keyname); 1240 } 1241 } 1242 return ERROR_SUCCESS; 1243 } 1244 1245 UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) 1246 { 1247 static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0}; 1248 HKEY hkey = NULL; 1249 MSIEXTENSION *ext; 1250 MSIRECORD *uirow; 1251 BOOL install_on_demand = TRUE; 1252 LONG res; 1253 UINT r; 1254 1255 r = load_classes_and_such( package ); 1256 if (r != ERROR_SUCCESS) 1257 return r; 1258 1259 /* We need to set install_on_demand based on if the shell handles advertised 1260 * shortcuts and the like. Because Mike McCormack is working on this i am 1261 * going to default to TRUE 1262 */ 1263 1264 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) 1265 { 1266 LPWSTR extension; 1267 MSIFEATURE *feature; 1268 1269 if (!ext->Component) 1270 continue; 1271 1272 if (!ext->Component->Enabled) 1273 { 1274 TRACE("component is disabled\n"); 1275 continue; 1276 } 1277 1278 feature = ext->Feature; 1279 if (!feature) 1280 continue; 1281 1282 /* 1283 * yes. MSDN says that these are based on _Feature_ not on 1284 * Component. So verify the feature is to be installed 1285 */ 1286 feature->Action = msi_get_feature_action( package, feature ); 1287 if (feature->Action != INSTALLSTATE_LOCAL && 1288 !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED)) 1289 { 1290 TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n", 1291 debugstr_w(feature->Feature), debugstr_w(ext->Extension)); 1292 continue; 1293 } 1294 TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext); 1295 1296 ext->Installed = TRUE; 1297 1298 /* this is only registered if the extension has at least 1 verb 1299 * according to MSDN 1300 */ 1301 if (ext->ProgID && !list_empty( &ext->verbs ) ) 1302 mark_progid_for_install( package, ext->ProgID ); 1303 1304 mark_mime_for_install(ext->Mime); 1305 1306 extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) ); 1307 if (extension) 1308 { 1309 extension[0] = '.'; 1310 strcpyW( extension + 1, ext->Extension ); 1311 res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey ); 1312 msi_free( extension ); 1313 if (res != ERROR_SUCCESS) 1314 WARN("Failed to create extension key %d\n", res); 1315 } 1316 1317 if (ext->Mime) 1318 msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType ); 1319 1320 if (ext->ProgID || ext->ProgIDText) 1321 { 1322 static const WCHAR szSN[] = 1323 {'\\','S','h','e','l','l','N','e','w',0}; 1324 HKEY hkey2; 1325 LPWSTR newkey; 1326 LPCWSTR progid; 1327 MSIVERB *verb; 1328 INT Sequence = MSI_NULL_INTEGER; 1329 1330 if (ext->ProgID) 1331 progid = ext->ProgID->ProgID; 1332 else 1333 progid = ext->ProgIDText; 1334 1335 msi_reg_set_val_str( hkey, NULL, progid ); 1336 1337 newkey = msi_alloc( (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 1338 1339 strcpyW(newkey,progid); 1340 strcatW(newkey,szSN); 1341 RegCreateKeyW(hkey,newkey,&hkey2); 1342 RegCloseKey(hkey2); 1343 1344 msi_free(newkey); 1345 1346 /* do all the verbs */ 1347 LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry ) 1348 { 1349 register_verb( package, progid, ext->Component, 1350 ext, verb, &Sequence); 1351 } 1352 } 1353 1354 RegCloseKey(hkey); 1355 1356 uirow = MSI_CreateRecord(1); 1357 MSI_RecordSetStringW( uirow, 1, ext->Extension ); 1358 msi_ui_actiondata( package, szRegisterExtensionInfo, uirow ); 1359 msiobj_release(&uirow->hdr); 1360 } 1361 return ERROR_SUCCESS; 1362 } 1363 1364 UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package ) 1365 { 1366 MSIEXTENSION *ext; 1367 MSIRECORD *uirow; 1368 LONG res; 1369 UINT r; 1370 1371 r = load_classes_and_such( package ); 1372 if (r != ERROR_SUCCESS) 1373 return r; 1374 1375 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) 1376 { 1377 LPWSTR extension; 1378 MSIFEATURE *feature; 1379 1380 if (!ext->Component) 1381 continue; 1382 1383 if (!ext->Component->Enabled) 1384 { 1385 TRACE("component is disabled\n"); 1386 continue; 1387 } 1388 1389 feature = ext->Feature; 1390 if (!feature) 1391 continue; 1392 1393 feature->Action = msi_get_feature_action( package, feature ); 1394 if (feature->Action != INSTALLSTATE_ABSENT) 1395 { 1396 TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n", 1397 debugstr_w(feature->Feature), debugstr_w(ext->Extension)); 1398 continue; 1399 } 1400 TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension)); 1401 1402 ext->Installed = FALSE; 1403 1404 if (ext->ProgID && !list_empty( &ext->verbs )) 1405 mark_progid_for_uninstall( package, ext->ProgID ); 1406 1407 mark_mime_for_uninstall( ext->Mime ); 1408 1409 extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) ); 1410 if (extension) 1411 { 1412 extension[0] = '.'; 1413 strcpyW( extension + 1, ext->Extension ); 1414 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension ); 1415 msi_free( extension ); 1416 if (res != ERROR_SUCCESS) 1417 WARN("Failed to delete extension key %d\n", res); 1418 } 1419 1420 if (ext->ProgID || ext->ProgIDText) 1421 { 1422 static const WCHAR shellW[] = {'\\','s','h','e','l','l',0}; 1423 LPCWSTR progid; 1424 LPWSTR progid_shell; 1425 1426 if (ext->ProgID) 1427 progid = ext->ProgID->ProgID; 1428 else 1429 progid = ext->ProgIDText; 1430 1431 progid_shell = msi_alloc( (strlenW( progid ) + strlenW( shellW ) + 1) * sizeof(WCHAR) ); 1432 if (progid_shell) 1433 { 1434 strcpyW( progid_shell, progid ); 1435 strcatW( progid_shell, shellW ); 1436 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell ); 1437 msi_free( progid_shell ); 1438 if (res != ERROR_SUCCESS) 1439 WARN("Failed to delete shell key %d\n", res); 1440 RegDeleteKeyW( HKEY_CLASSES_ROOT, progid ); 1441 } 1442 } 1443 1444 uirow = MSI_CreateRecord( 1 ); 1445 MSI_RecordSetStringW( uirow, 1, ext->Extension ); 1446 msi_ui_actiondata( package, szUnregisterExtensionInfo, uirow ); 1447 msiobj_release( &uirow->hdr ); 1448 } 1449 return ERROR_SUCCESS; 1450 } 1451 1452 UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) 1453 { 1454 static const WCHAR szExtension[] = {'E','x','t','e','n','s','i','o','n',0}; 1455 MSIRECORD *uirow; 1456 MSIMIME *mt; 1457 UINT r; 1458 1459 r = load_classes_and_such( package ); 1460 if (r != ERROR_SUCCESS) 1461 return r; 1462 1463 LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry ) 1464 { 1465 LPWSTR extension, key; 1466 1467 /* 1468 * check if the MIME is to be installed. Either as requested by an 1469 * extension or Class 1470 */ 1471 mt->InstallMe = (mt->InstallMe || 1472 (mt->Class && mt->Class->Installed) || 1473 (mt->Extension && mt->Extension->Installed)); 1474 1475 if (!mt->InstallMe) 1476 { 1477 TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType)); 1478 continue; 1479 } 1480 1481 TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType)); 1482 1483 extension = msi_alloc( (strlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) ); 1484 key = msi_alloc( (strlenW( mt->ContentType ) + strlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) ); 1485 1486 if (extension && key) 1487 { 1488 extension[0] = '.'; 1489 strcpyW( extension + 1, mt->Extension->Extension ); 1490 1491 strcpyW( key, szMIMEDatabase ); 1492 strcatW( key, mt->ContentType ); 1493 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExtension, extension ); 1494 1495 if (mt->clsid) 1496 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid ); 1497 } 1498 msi_free( extension ); 1499 msi_free( key ); 1500 1501 uirow = MSI_CreateRecord( 2 ); 1502 MSI_RecordSetStringW( uirow, 1, mt->ContentType ); 1503 MSI_RecordSetStringW( uirow, 2, mt->suffix ); 1504 msi_ui_actiondata( package, szRegisterMIMEInfo, uirow ); 1505 msiobj_release( &uirow->hdr ); 1506 } 1507 return ERROR_SUCCESS; 1508 } 1509 1510 UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package ) 1511 { 1512 MSIRECORD *uirow; 1513 MSIMIME *mime; 1514 UINT r; 1515 1516 r = load_classes_and_such( package ); 1517 if (r != ERROR_SUCCESS) 1518 return r; 1519 1520 LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry ) 1521 { 1522 LONG res; 1523 LPWSTR mime_key; 1524 1525 mime->InstallMe = (mime->InstallMe || 1526 (mime->Class && mime->Class->Installed) || 1527 (mime->Extension && mime->Extension->Installed)); 1528 1529 if (mime->InstallMe) 1530 { 1531 TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType)); 1532 continue; 1533 } 1534 1535 TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType)); 1536 1537 mime_key = msi_alloc( (strlenW( szMIMEDatabase ) + strlenW( mime->ContentType ) + 1) * sizeof(WCHAR) ); 1538 if (mime_key) 1539 { 1540 strcpyW( mime_key, szMIMEDatabase ); 1541 strcatW( mime_key, mime->ContentType ); 1542 res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key ); 1543 if (res != ERROR_SUCCESS) 1544 WARN("Failed to delete MIME key %d\n", res); 1545 msi_free( mime_key ); 1546 } 1547 1548 uirow = MSI_CreateRecord( 2 ); 1549 MSI_RecordSetStringW( uirow, 1, mime->ContentType ); 1550 MSI_RecordSetStringW( uirow, 2, mime->suffix ); 1551 msi_ui_actiondata( package, szUnregisterMIMEInfo, uirow ); 1552 msiobj_release( &uirow->hdr ); 1553 } 1554 return ERROR_SUCCESS; 1555 } 1556