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