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