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 cls->action = INSTALLSTATE_UNKNOWN; 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 ext->action = INSTALLSTATE_UNKNOWN; 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 UINT register_appid(const MSIAPPID *appid, LPCWSTR app ) 693 { 694 static const WCHAR szRemoteServerName[] = 695 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0}; 696 static const WCHAR szLocalService[] = 697 {'L','o','c','a','l','S','e','r','v','i','c','e',0}; 698 static const WCHAR szService[] = 699 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0}; 700 static const WCHAR szDLL[] = 701 {'D','l','l','S','u','r','r','o','g','a','t','e',0}; 702 static const WCHAR szActivate[] = 703 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0}; 704 static const WCHAR szY[] = {'Y',0}; 705 static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; 706 static const WCHAR szUser[] = 707 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0}; 708 709 HKEY hkey2,hkey3; 710 711 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); 712 RegCreateKeyW( hkey2, appid->AppID, &hkey3 ); 713 RegCloseKey(hkey2); 714 msi_reg_set_val_str( hkey3, NULL, app ); 715 716 if (appid->RemoteServerName) 717 msi_reg_set_val_str( hkey3, szRemoteServerName, appid->RemoteServerName ); 718 719 if (appid->LocalServer) 720 msi_reg_set_val_str( hkey3, szLocalService, appid->LocalServer ); 721 722 if (appid->ServiceParameters) 723 msi_reg_set_val_str( hkey3, szService, appid->ServiceParameters ); 724 725 if (appid->DllSurrogate) 726 msi_reg_set_val_str( hkey3, szDLL, appid->DllSurrogate ); 727 728 if (appid->ActivateAtStorage) 729 msi_reg_set_val_str( hkey3, szActivate, szY ); 730 731 if (appid->RunAsInteractiveUser) 732 msi_reg_set_val_str( hkey3, szRunAs, szUser ); 733 734 RegCloseKey(hkey3); 735 return ERROR_SUCCESS; 736 } 737 738 UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) 739 { 740 static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0}; 741 const WCHAR *keypath; 742 MSIRECORD *uirow; 743 HKEY hkey, hkey2, hkey3; 744 MSICLASS *cls; 745 UINT r; 746 747 r = load_classes_and_such( package ); 748 if (r != ERROR_SUCCESS) 749 return r; 750 751 if (is_64bit && package->platform == PLATFORM_INTEL) 752 keypath = szWow6432NodeCLSID; 753 else 754 keypath = szCLSID; 755 756 if (RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, &hkey) != ERROR_SUCCESS) 757 return ERROR_FUNCTION_FAILED; 758 759 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) 760 { 761 MSICOMPONENT *comp; 762 MSIFILE *file; 763 DWORD size; 764 LPWSTR argument; 765 MSIFEATURE *feature; 766 767 comp = cls->Component; 768 if ( !comp ) 769 continue; 770 771 if (!comp->Enabled) 772 { 773 TRACE("component is disabled\n"); 774 continue; 775 } 776 777 feature = cls->Feature; 778 if (!feature) 779 continue; 780 781 feature->Action = msi_get_feature_action( package, feature ); 782 if (feature->Action != INSTALLSTATE_LOCAL && 783 feature->Action != INSTALLSTATE_ADVERTISED ) 784 { 785 TRACE("feature %s not scheduled for installation, skipping registration of class %s\n", 786 debugstr_w(feature->Feature), debugstr_w(cls->clsid)); 787 continue; 788 } 789 790 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath ))) 791 { 792 TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid)); 793 continue; 794 } 795 TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls); 796 797 cls->action = INSTALLSTATE_LOCAL; 798 799 RegCreateKeyW( hkey, cls->clsid, &hkey2 ); 800 801 if (cls->Description) 802 msi_reg_set_val_str( hkey2, NULL, cls->Description ); 803 804 RegCreateKeyW( hkey2, cls->Context, &hkey3 ); 805 806 /* 807 * FIXME: Implement install on demand (advertised components). 808 * 809 * ole32.dll should call msi.MsiProvideComponentFromDescriptor() 810 * when it needs an InProcServer that doesn't exist. 811 * The component advertise string should be in the "InProcServer" value. 812 */ 813 size = lstrlenW( file->TargetPath )+1; 814 if (cls->Argument) 815 size += lstrlenW(cls->Argument)+1; 816 817 argument = msi_alloc( size * sizeof(WCHAR) ); 818 lstrcpyW( argument, file->TargetPath ); 819 820 if (cls->Argument) 821 { 822 lstrcatW( argument, szSpace ); 823 lstrcatW( argument, cls->Argument ); 824 } 825 826 msi_reg_set_val_str( hkey3, NULL, argument ); 827 msi_free(argument); 828 829 RegCloseKey(hkey3); 830 831 if (cls->ProgID || cls->ProgIDText) 832 { 833 LPCWSTR progid; 834 835 if (cls->ProgID) 836 progid = cls->ProgID->ProgID; 837 else 838 progid = cls->ProgIDText; 839 840 msi_reg_set_subkey_val( hkey2, szProgID, NULL, progid ); 841 842 if (cls->ProgID && cls->ProgID->VersionInd) 843 { 844 msi_reg_set_subkey_val( hkey2, szVIProgID, NULL, 845 cls->ProgID->VersionInd->ProgID ); 846 } 847 } 848 849 if (cls->AppID) 850 { 851 MSIAPPID *appid = cls->AppID; 852 msi_reg_set_val_str( hkey2, szAppID, appid->AppID ); 853 register_appid( appid, cls->Description ); 854 } 855 856 if (cls->IconPath) 857 msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath ); 858 859 if (cls->DefInprocHandler) 860 msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler ); 861 862 if (cls->DefInprocHandler32) 863 msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 ); 864 865 RegCloseKey(hkey2); 866 867 /* if there is a FileTypeMask, register the FileType */ 868 if (cls->FileTypeMask) 869 { 870 LPWSTR ptr, ptr2; 871 LPWSTR keyname; 872 INT index = 0; 873 ptr = cls->FileTypeMask; 874 while (ptr && *ptr) 875 { 876 ptr2 = strchrW(ptr,';'); 877 if (ptr2) 878 *ptr2 = 0; 879 keyname = msi_alloc( (strlenW(szFileType_fmt) + strlenW(cls->clsid) + 4) * sizeof(WCHAR)); 880 sprintfW( keyname, szFileType_fmt, cls->clsid, index ); 881 882 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, ptr ); 883 msi_free(keyname); 884 885 if (ptr2) 886 ptr = ptr2+1; 887 else 888 ptr = NULL; 889 890 index ++; 891 } 892 } 893 894 uirow = MSI_CreateRecord(1); 895 MSI_RecordSetStringW( uirow, 1, cls->clsid ); 896 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 897 msiobj_release(&uirow->hdr); 898 } 899 RegCloseKey(hkey); 900 return ERROR_SUCCESS; 901 } 902 903 UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package ) 904 { 905 static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0}; 906 const WCHAR *keypath; 907 MSIRECORD *uirow; 908 MSICLASS *cls; 909 HKEY hkey, hkey2; 910 UINT r; 911 912 r = load_classes_and_such( package ); 913 if (r != ERROR_SUCCESS) 914 return r; 915 916 if (is_64bit && package->platform == PLATFORM_INTEL) 917 keypath = szWow6432NodeCLSID; 918 else 919 keypath = szCLSID; 920 921 if (RegOpenKeyW( HKEY_CLASSES_ROOT, keypath, &hkey ) != ERROR_SUCCESS) 922 return ERROR_SUCCESS; 923 924 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) 925 { 926 MSIFEATURE *feature; 927 MSICOMPONENT *comp; 928 LPWSTR filetype; 929 LONG res; 930 931 comp = cls->Component; 932 if (!comp) 933 continue; 934 935 if (!comp->Enabled) 936 { 937 TRACE("component is disabled\n"); 938 continue; 939 } 940 941 feature = cls->Feature; 942 if (!feature) 943 continue; 944 945 feature->Action = msi_get_feature_action( package, feature ); 946 if (feature->Action != INSTALLSTATE_ABSENT) 947 { 948 TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n", 949 debugstr_w(feature->Feature), debugstr_w(cls->clsid)); 950 continue; 951 } 952 TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls); 953 954 cls->action = INSTALLSTATE_ABSENT; 955 956 res = RegDeleteTreeW( hkey, cls->clsid ); 957 if (res != ERROR_SUCCESS) 958 WARN("Failed to delete class key %d\n", res); 959 960 if (cls->AppID) 961 { 962 res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 ); 963 if (res == ERROR_SUCCESS) 964 { 965 res = RegDeleteKeyW( hkey2, cls->AppID->AppID ); 966 if (res != ERROR_SUCCESS) 967 WARN("Failed to delete appid key %d\n", res); 968 RegCloseKey( hkey2 ); 969 } 970 } 971 if (cls->FileTypeMask) 972 { 973 filetype = msi_alloc( (strlenW( szFileType ) + strlenW( cls->clsid ) + 1) * sizeof(WCHAR) ); 974 if (filetype) 975 { 976 strcpyW( filetype, szFileType ); 977 strcatW( filetype, cls->clsid ); 978 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype ); 979 msi_free( filetype ); 980 981 if (res != ERROR_SUCCESS) 982 WARN("Failed to delete file type %d\n", res); 983 } 984 } 985 986 uirow = MSI_CreateRecord( 1 ); 987 MSI_RecordSetStringW( uirow, 1, cls->clsid ); 988 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 989 msiobj_release( &uirow->hdr ); 990 } 991 RegCloseKey( hkey ); 992 return ERROR_SUCCESS; 993 } 994 995 static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid ) 996 { 997 while (progid) 998 { 999 if (progid->Class) 1000 return progid->Class->clsid; 1001 if (progid->Parent == progid) 1002 break; 1003 progid = progid->Parent; 1004 } 1005 return NULL; 1006 } 1007 1008 static UINT register_progid( const MSIPROGID* progid ) 1009 { 1010 static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0}; 1011 HKEY hkey = 0; 1012 UINT rc; 1013 1014 rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey ); 1015 if (rc == ERROR_SUCCESS) 1016 { 1017 LPCWSTR clsid = get_clsid_of_progid( progid ); 1018 1019 if (clsid) 1020 msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid ); 1021 else 1022 TRACE("%s has no class\n", debugstr_w( progid->ProgID ) ); 1023 1024 if (progid->Description) 1025 msi_reg_set_val_str( hkey, NULL, progid->Description ); 1026 1027 if (progid->IconPath) 1028 msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath ); 1029 1030 /* write out the current version */ 1031 if (progid->CurVer) 1032 msi_reg_set_subkey_val( hkey, szCurVer, NULL, progid->CurVer->ProgID ); 1033 1034 RegCloseKey(hkey); 1035 } 1036 else 1037 ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) ); 1038 1039 return rc; 1040 } 1041 1042 static const MSICLASS *get_progid_class( const MSIPROGID *progid ) 1043 { 1044 while (progid) 1045 { 1046 if (progid->Parent) progid = progid->Parent; 1047 if (progid->Class) return progid->Class; 1048 if (!progid->Parent || progid->Parent == progid) break; 1049 } 1050 return NULL; 1051 } 1052 1053 static BOOL has_class_installed( const MSIPROGID *progid ) 1054 { 1055 const MSICLASS *class = get_progid_class( progid ); 1056 if (!class || !class->ProgID) return FALSE; 1057 return (class->action == INSTALLSTATE_LOCAL); 1058 } 1059 1060 static BOOL has_one_extension_installed( const MSIPACKAGE *package, const MSIPROGID *progid ) 1061 { 1062 const MSIEXTENSION *extension; 1063 LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry ) 1064 { 1065 if (extension->ProgID == progid && !list_empty( &extension->verbs ) && 1066 extension->action == INSTALLSTATE_LOCAL) return TRUE; 1067 } 1068 return FALSE; 1069 } 1070 1071 UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) 1072 { 1073 MSIPROGID *progid; 1074 MSIRECORD *uirow; 1075 UINT r; 1076 1077 r = load_classes_and_such( package ); 1078 if (r != ERROR_SUCCESS) 1079 return r; 1080 1081 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) 1082 { 1083 if (!has_class_installed( progid ) && !has_one_extension_installed( package, progid )) 1084 { 1085 TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid->ProgID)); 1086 continue; 1087 } 1088 TRACE("Registering progid %s\n", debugstr_w(progid->ProgID)); 1089 1090 register_progid( progid ); 1091 1092 uirow = MSI_CreateRecord( 1 ); 1093 MSI_RecordSetStringW( uirow, 1, progid->ProgID ); 1094 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 1095 msiobj_release( &uirow->hdr ); 1096 } 1097 return ERROR_SUCCESS; 1098 } 1099 1100 static BOOL has_class_removed( const MSIPROGID *progid ) 1101 { 1102 const MSICLASS *class = get_progid_class( progid ); 1103 if (!class || !class->ProgID) return FALSE; 1104 return (class->action == INSTALLSTATE_ABSENT); 1105 } 1106 1107 static BOOL has_extensions( const MSIPACKAGE *package, const MSIPROGID *progid ) 1108 { 1109 const MSIEXTENSION *extension; 1110 LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry ) 1111 { 1112 if (extension->ProgID == progid && !list_empty( &extension->verbs )) return TRUE; 1113 } 1114 return FALSE; 1115 } 1116 1117 static BOOL has_all_extensions_removed( const MSIPACKAGE *package, const MSIPROGID *progid ) 1118 { 1119 BOOL ret = FALSE; 1120 const MSIEXTENSION *extension; 1121 LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry ) 1122 { 1123 if (extension->ProgID == progid && !list_empty( &extension->verbs ) && 1124 extension->action == INSTALLSTATE_ABSENT) ret = TRUE; 1125 else ret = FALSE; 1126 } 1127 return ret; 1128 } 1129 1130 UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package ) 1131 { 1132 MSIPROGID *progid; 1133 MSIRECORD *uirow; 1134 LONG res; 1135 UINT r; 1136 1137 r = load_classes_and_such( package ); 1138 if (r != ERROR_SUCCESS) 1139 return r; 1140 1141 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) 1142 { 1143 if (!has_class_removed( progid ) || 1144 (has_extensions( package, progid ) && !has_all_extensions_removed( package, progid ))) 1145 { 1146 TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID)); 1147 continue; 1148 } 1149 TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID)); 1150 1151 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID ); 1152 if (res != ERROR_SUCCESS) 1153 TRACE("Failed to delete progid key %d\n", res); 1154 1155 uirow = MSI_CreateRecord( 1 ); 1156 MSI_RecordSetStringW( uirow, 1, progid->ProgID ); 1157 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 1158 msiobj_release( &uirow->hdr ); 1159 } 1160 return ERROR_SUCCESS; 1161 } 1162 1163 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 1164 MSICOMPONENT* component, const MSIEXTENSION* extension, 1165 MSIVERB* verb, INT* Sequence ) 1166 { 1167 LPWSTR keyname; 1168 HKEY key; 1169 static const WCHAR szShell[] = {'s','h','e','l','l',0}; 1170 static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0}; 1171 static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0}; 1172 static const WCHAR fmt2[] = {'\"','%','s','\"',0}; 1173 LPWSTR command; 1174 DWORD size; 1175 LPWSTR advertise; 1176 1177 keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand); 1178 1179 TRACE("Making Key %s\n",debugstr_w(keyname)); 1180 RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); 1181 size = strlenW(component->FullKeypath); 1182 if (verb->Argument) 1183 size += strlenW(verb->Argument); 1184 size += 4; 1185 1186 command = msi_alloc(size * sizeof (WCHAR)); 1187 if (verb->Argument) 1188 sprintfW(command, fmt, component->FullKeypath, verb->Argument); 1189 else 1190 sprintfW(command, fmt2, component->FullKeypath); 1191 1192 msi_reg_set_val_str( key, NULL, command ); 1193 msi_free(command); 1194 1195 advertise = msi_create_component_advertise_string(package, component, 1196 extension->Feature->Feature); 1197 size = strlenW(advertise); 1198 1199 if (verb->Argument) 1200 size += strlenW(verb->Argument); 1201 size += 4; 1202 1203 command = msi_alloc_zero(size * sizeof (WCHAR)); 1204 1205 strcpyW(command,advertise); 1206 if (verb->Argument) 1207 { 1208 strcatW(command,szSpace); 1209 strcatW(command,verb->Argument); 1210 } 1211 1212 msi_reg_set_val_multi_str( key, szCommand, command ); 1213 1214 RegCloseKey(key); 1215 msi_free(keyname); 1216 msi_free(advertise); 1217 msi_free(command); 1218 1219 if (verb->Command) 1220 { 1221 keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb ); 1222 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command ); 1223 msi_free(keyname); 1224 } 1225 1226 if (verb->Sequence != MSI_NULL_INTEGER) 1227 { 1228 if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence) 1229 { 1230 *Sequence = verb->Sequence; 1231 keyname = msi_build_directory_name( 2, progid, szShell ); 1232 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb ); 1233 msi_free(keyname); 1234 } 1235 } 1236 return ERROR_SUCCESS; 1237 } 1238 1239 UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) 1240 { 1241 static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0}; 1242 HKEY hkey = NULL; 1243 MSIEXTENSION *ext; 1244 MSIRECORD *uirow; 1245 BOOL install_on_demand = TRUE; 1246 LONG res; 1247 UINT r; 1248 1249 r = load_classes_and_such( package ); 1250 if (r != ERROR_SUCCESS) 1251 return r; 1252 1253 /* We need to set install_on_demand based on if the shell handles advertised 1254 * shortcuts and the like. Because Mike McCormack is working on this i am 1255 * going to default to TRUE 1256 */ 1257 1258 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) 1259 { 1260 LPWSTR extension; 1261 MSIFEATURE *feature; 1262 1263 if (!ext->Component) 1264 continue; 1265 1266 if (!ext->Component->Enabled) 1267 { 1268 TRACE("component is disabled\n"); 1269 continue; 1270 } 1271 1272 feature = ext->Feature; 1273 if (!feature) 1274 continue; 1275 1276 /* 1277 * yes. MSDN says that these are based on _Feature_ not on 1278 * Component. So verify the feature is to be installed 1279 */ 1280 feature->Action = msi_get_feature_action( package, feature ); 1281 if (feature->Action != INSTALLSTATE_LOCAL && 1282 !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED)) 1283 { 1284 TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n", 1285 debugstr_w(feature->Feature), debugstr_w(ext->Extension)); 1286 continue; 1287 } 1288 TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext); 1289 1290 ext->action = INSTALLSTATE_LOCAL; 1291 1292 extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) ); 1293 if (extension) 1294 { 1295 extension[0] = '.'; 1296 strcpyW( extension + 1, ext->Extension ); 1297 res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey ); 1298 msi_free( extension ); 1299 if (res != ERROR_SUCCESS) 1300 WARN("Failed to create extension key %d\n", res); 1301 } 1302 1303 if (ext->Mime) 1304 msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType ); 1305 1306 if (ext->ProgID || ext->ProgIDText) 1307 { 1308 static const WCHAR szSN[] = 1309 {'\\','S','h','e','l','l','N','e','w',0}; 1310 HKEY hkey2; 1311 LPWSTR newkey; 1312 LPCWSTR progid; 1313 MSIVERB *verb; 1314 INT Sequence = MSI_NULL_INTEGER; 1315 1316 if (ext->ProgID) 1317 progid = ext->ProgID->ProgID; 1318 else 1319 progid = ext->ProgIDText; 1320 1321 msi_reg_set_val_str( hkey, NULL, progid ); 1322 1323 newkey = msi_alloc( (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 1324 1325 strcpyW(newkey,progid); 1326 strcatW(newkey,szSN); 1327 RegCreateKeyW(hkey,newkey,&hkey2); 1328 RegCloseKey(hkey2); 1329 1330 msi_free(newkey); 1331 1332 /* do all the verbs */ 1333 LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry ) 1334 { 1335 register_verb( package, progid, ext->Component, 1336 ext, verb, &Sequence); 1337 } 1338 } 1339 1340 RegCloseKey(hkey); 1341 1342 uirow = MSI_CreateRecord(1); 1343 MSI_RecordSetStringW( uirow, 1, ext->Extension ); 1344 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 1345 msiobj_release(&uirow->hdr); 1346 } 1347 return ERROR_SUCCESS; 1348 } 1349 1350 UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package ) 1351 { 1352 MSIEXTENSION *ext; 1353 MSIRECORD *uirow; 1354 LONG res; 1355 UINT r; 1356 1357 r = load_classes_and_such( package ); 1358 if (r != ERROR_SUCCESS) 1359 return r; 1360 1361 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) 1362 { 1363 LPWSTR extension; 1364 MSIFEATURE *feature; 1365 1366 if (!ext->Component) 1367 continue; 1368 1369 if (!ext->Component->Enabled) 1370 { 1371 TRACE("component is disabled\n"); 1372 continue; 1373 } 1374 1375 feature = ext->Feature; 1376 if (!feature) 1377 continue; 1378 1379 feature->Action = msi_get_feature_action( package, feature ); 1380 if (feature->Action != INSTALLSTATE_ABSENT) 1381 { 1382 TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n", 1383 debugstr_w(feature->Feature), debugstr_w(ext->Extension)); 1384 continue; 1385 } 1386 TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension)); 1387 1388 ext->action = INSTALLSTATE_ABSENT; 1389 1390 extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) ); 1391 if (extension) 1392 { 1393 extension[0] = '.'; 1394 strcpyW( extension + 1, ext->Extension ); 1395 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension ); 1396 msi_free( extension ); 1397 if (res != ERROR_SUCCESS) 1398 WARN("Failed to delete extension key %d\n", res); 1399 } 1400 1401 if (ext->ProgID || ext->ProgIDText) 1402 { 1403 static const WCHAR shellW[] = {'\\','s','h','e','l','l',0}; 1404 LPCWSTR progid; 1405 LPWSTR progid_shell; 1406 1407 if (ext->ProgID) 1408 progid = ext->ProgID->ProgID; 1409 else 1410 progid = ext->ProgIDText; 1411 1412 progid_shell = msi_alloc( (strlenW( progid ) + strlenW( shellW ) + 1) * sizeof(WCHAR) ); 1413 if (progid_shell) 1414 { 1415 strcpyW( progid_shell, progid ); 1416 strcatW( progid_shell, shellW ); 1417 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell ); 1418 msi_free( progid_shell ); 1419 if (res != ERROR_SUCCESS) 1420 WARN("Failed to delete shell key %d\n", res); 1421 RegDeleteKeyW( HKEY_CLASSES_ROOT, progid ); 1422 } 1423 } 1424 1425 uirow = MSI_CreateRecord( 1 ); 1426 MSI_RecordSetStringW( uirow, 1, ext->Extension ); 1427 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 1428 msiobj_release( &uirow->hdr ); 1429 } 1430 return ERROR_SUCCESS; 1431 } 1432 1433 UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) 1434 { 1435 static const WCHAR szExtension[] = {'E','x','t','e','n','s','i','o','n',0}; 1436 MSIRECORD *uirow; 1437 MSIMIME *mt; 1438 UINT r; 1439 1440 r = load_classes_and_such( package ); 1441 if (r != ERROR_SUCCESS) 1442 return r; 1443 1444 LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry ) 1445 { 1446 LPWSTR extension = NULL, key; 1447 1448 /* 1449 * check if the MIME is to be installed. Either as requested by an 1450 * extension or Class 1451 */ 1452 if ((!mt->Class || mt->Class->action != INSTALLSTATE_LOCAL) && 1453 (!mt->Extension || mt->Extension->action != INSTALLSTATE_LOCAL)) 1454 { 1455 TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType)); 1456 continue; 1457 } 1458 1459 TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType)); 1460 1461 if (mt->Extension) extension = msi_alloc( (strlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) ); 1462 key = msi_alloc( (strlenW( mt->ContentType ) + strlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) ); 1463 1464 if (extension && key) 1465 { 1466 extension[0] = '.'; 1467 strcpyW( extension + 1, mt->Extension->Extension ); 1468 1469 strcpyW( key, szMIMEDatabase ); 1470 strcatW( key, mt->ContentType ); 1471 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExtension, extension ); 1472 1473 if (mt->clsid) 1474 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid ); 1475 } 1476 msi_free( extension ); 1477 msi_free( key ); 1478 1479 uirow = MSI_CreateRecord( 2 ); 1480 MSI_RecordSetStringW( uirow, 1, mt->ContentType ); 1481 MSI_RecordSetStringW( uirow, 2, mt->suffix ); 1482 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 1483 msiobj_release( &uirow->hdr ); 1484 } 1485 return ERROR_SUCCESS; 1486 } 1487 1488 UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package ) 1489 { 1490 MSIRECORD *uirow; 1491 MSIMIME *mime; 1492 UINT r; 1493 1494 r = load_classes_and_such( package ); 1495 if (r != ERROR_SUCCESS) 1496 return r; 1497 1498 LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry ) 1499 { 1500 LONG res; 1501 LPWSTR mime_key; 1502 1503 if ((!mime->Class || mime->Class->action != INSTALLSTATE_ABSENT) && 1504 (!mime->Extension || mime->Extension->action != INSTALLSTATE_ABSENT)) 1505 { 1506 TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType)); 1507 continue; 1508 } 1509 1510 TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType)); 1511 1512 mime_key = msi_alloc( (strlenW( szMIMEDatabase ) + strlenW( mime->ContentType ) + 1) * sizeof(WCHAR) ); 1513 if (mime_key) 1514 { 1515 strcpyW( mime_key, szMIMEDatabase ); 1516 strcatW( mime_key, mime->ContentType ); 1517 res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key ); 1518 if (res != ERROR_SUCCESS) 1519 WARN("Failed to delete MIME key %d\n", res); 1520 msi_free( mime_key ); 1521 } 1522 1523 uirow = MSI_CreateRecord( 2 ); 1524 MSI_RecordSetStringW( uirow, 1, mime->ContentType ); 1525 MSI_RecordSetStringW( uirow, 2, mime->suffix ); 1526 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow); 1527 msiobj_release( &uirow->hdr ); 1528 } 1529 return ERROR_SUCCESS; 1530 } 1531