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