classes.c 42.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Implementation of the Microsoft Installer (msi.dll)
 *
 * Copyright 2005 Aric Stewart for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22
/* Actions handled in this module:
 *
23 24 25 26
 * RegisterClassInfo
 * RegisterProgIdInfo
 * RegisterExtensionInfo
 * RegisterMIMEInfo
27 28 29
 * UnregisterClassInfo
 * UnregisterProgIdInfo
 * UnregisterExtensionInfo
30
 * UnregisterMIMEInfo
31 32 33 34 35 36 37 38 39 40 41 42 43 44
 */

#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
#include "wine/debug.h"
#include "msipriv.h"
#include "winuser.h"

WINE_DEFAULT_DEBUG_CHANNEL(msi);

45
static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row )
46 47
{
    LPCWSTR buffer;
48
    MSIAPPID *appid;
49 50 51

    /* fill in the data */

52
    appid = msi_alloc_zero( sizeof(MSIAPPID) );
53 54
    if (!appid)
        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 63 64
    appid->LocalServer = msi_dup_record_field(row,3);
    appid->ServiceParameters = msi_dup_record_field(row,4);
    appid->DllSurrogate = msi_dup_record_field(row,5);
65

66 67 68 69
    appid->ActivateAtStorage = !MSI_RecordIsNull(row,6);
    appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7);

    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 80
    if (!name)
        return NULL;
81 82

    /* check for appids already loaded */
83 84
    LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry )
    {
85
        if (!wcsicmp( appid->AppID, name ))
86
        {
87 88
            TRACE("found appid %s %p\n", debugstr_w(name), appid);
            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 108 109 110
    LPCWSTR buffer;

    /* fill in the data */

111
    progid = msi_alloc_zero( sizeof(MSIPROGID) );
112 113
    if (!progid)
        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 122
    progid->Parent = load_given_progid(package,buffer);
    if (progid->Parent == NULL && buffer)
123 124 125
        FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));

    buffer = MSI_RecordGetString(row,3);
126 127
    progid->Class = load_given_class(package,buffer);
    if (progid->Class == NULL && buffer)
128 129
        FIXME("Unknown class %s\n",debugstr_w(buffer));

130
    progid->Description = msi_dup_record_field(row,4);
131 132 133

    if (!MSI_RecordIsNull(row,6))
    {
134
        INT icon_index = MSI_RecordGetInteger(row,6);
135
        LPCWSTR FileName = MSI_RecordGetString(row,5);
136 137
        LPWSTR FilePath;

138
        FilePath = msi_build_icon_path(package, FileName);
139

140 141
        progid->IconPath = msi_alloc( (lstrlenW(FilePath) + 10) * sizeof(WCHAR) );
        swprintf( progid->IconPath, lstrlenW(FilePath) + 10, L"%s,%d", FilePath, icon_index );
142
        msi_free(FilePath);
143 144 145 146 147
    }
    else
    {
        buffer = MSI_RecordGetString(row,5);
        if (buffer)
148
            progid->IconPath = msi_build_icon_path(package, buffer);
149 150
    }

151 152
    progid->CurVer = NULL;
    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 158
        MSIPROGID *parent = progid->Parent;

159
        while (parent->Parent && parent->Parent != parent)
160
            parent = parent->Parent;
161

Austin English's avatar
Austin English committed
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 175
    MSIRECORD *row;

176 177
    if (!name)
        return NULL;
178 179

    /* check for progids already loaded */
180 181
    LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
    {
182
        if (!wcsicmp( progid->ProgID, name ))
183
        {
184 185
            TRACE("found progid %s (%p)\n",debugstr_w(name), progid );
            return progid;
186
        }
187
    }
188 189

    row = MSI_QueryGetRecord( package->db, L"SELECT * FROM `ProgId` WHERE `ProgId` = '%s'", name );
190 191
    if (!row)
        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 203 204 205
    LPCWSTR buffer;

    /* fill in the data */

206
    cls = msi_alloc_zero( sizeof(MSICLASS) );
207 208
    if (!cls)
        return NULL;
209

210 211
    list_add_tail( &package->classes, &cls->entry );

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 224

    buffer = MSI_RecordGetString(row,6);
    if (buffer)
225
        cls->AppID = load_given_appid(package, buffer);
226

227
    cls->FileTypeMask = msi_dup_record_field(row,7);
228 229 230 231

    if (!MSI_RecordIsNull(row,9))
    {

232
        INT icon_index = MSI_RecordGetInteger(row,9);
233
        LPCWSTR FileName = MSI_RecordGetString(row,8);
234 235
        LPWSTR FilePath;

236
        FilePath = msi_build_icon_path(package, FileName);
237

238 239
        cls->IconPath = msi_alloc( (lstrlenW(FilePath) + 5) * sizeof(WCHAR) );
        swprintf( cls->IconPath, lstrlenW(FilePath) + 5, L"%s,%d", FilePath, icon_index );
240
        msi_free(FilePath);
241 242 243 244 245
    }
    else
    {
        buffer = MSI_RecordGetString(row,8);
        if (buffer)
246
            cls->IconPath = msi_build_icon_path(package, buffer);
247 248 249 250 251 252 253 254 255 256
    }

    if (!MSI_RecordIsNull(row,10))
    {
        i = MSI_RecordGetInteger(row,10);
        if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
        {
            switch(i)
            {
                case 1:
257
                    cls->DefInprocHandler = strdupW(L"ole2.dll");
258 259
                    break;
                case 2:
260
                    cls->DefInprocHandler32 = strdupW(L"ole32.dll");
261 262
                    break;
                case 3:
263 264
                    cls->DefInprocHandler = strdupW(L"ole2.dll");
                    cls->DefInprocHandler32 = strdupW(L"ole32.dll");
265 266 267 268 269
                    break;
            }
        }
        else
        {
270 271
            cls->DefInprocHandler32 = msi_dup_record_field( row, 10 );
            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 288
 * referenced through the first CLSID key. However when loading
 * 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 295 296
    MSIRECORD *row;

    if (!classid)
297
        return NULL;
298

299
    /* check for classes already loaded */
300 301
    LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
    {
302
        if (!wcsicmp( cls->clsid, classid ))
303
        {
304 305
            TRACE("found class %s (%p)\n",debugstr_w(classid), cls);
            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 326

    /* fill in the data */

327
    mt = msi_alloc_zero( sizeof(MSIMIME) );
328 329
    if (!mt)
        return mt;
330

331
    mt->ContentType = msi_dup_record_field( row, 1 );
332
    TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
333

334 335 336
    extension = MSI_RecordGetString( row, 2 );
    mt->Extension = load_given_extension( package, extension );
    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 356
    LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
    {
357
        if (!wcsicmp( mt->ContentType, mime ))
358
        {
359 360
            TRACE("found mime %s (%p)\n",debugstr_w(mime), mt);
            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 377 378 379
    LPCWSTR buffer;

    /* fill in the data */

380
    ext = msi_alloc_zero( sizeof(MSIEXTENSION) );
381 382 383
    if (!ext)
        return NULL;

384 385
    list_init( &ext->verbs );

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 398
    buffer = MSI_RecordGetString( row, 4 );
    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
Austin English's avatar
Austin English committed
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 416
    if (!name)
        return NULL;
417

418 419 420
    if (name[0] == '.')
        name++;

421
    /* check for extensions already loaded */
422 423
    LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
    {
424
        if (!wcsicmp( ext->Extension, name ))
425
        {
426 427
            TRACE("extension %s already loaded %p\n", debugstr_w(name), ext);
            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 441
}

static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
{
442
    MSIPACKAGE* package = param;
443
    MSIVERB *verb;
444
    LPCWSTR buffer;
445
    MSIEXTENSION *extension;
446 447

    buffer = MSI_RecordGetString(row,1);
448 449 450
    extension = load_given_extension( package, buffer );
    if (!extension)
    {
451
        ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
452 453 454 455
        return ERROR_SUCCESS;
    }

    /* fill in the data */
456

457
    verb = msi_alloc_zero( sizeof(MSIVERB) );
458 459 460
    if (!verb)
        return ERROR_OUTOFMEMORY;

461
    verb->Verb = msi_dup_record_field(row,2);
462 463
    TRACE("loading verb %s\n",debugstr_w(verb->Verb));
    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

Austin English's avatar
Austin English committed
471
    /* associate the verb with the correct extension */
472
    list_add_tail( &extension->verbs, &verb->entry );
473

474 475 476 477 478
    return ERROR_SUCCESS;
}

static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
{
479
    MSICOMPONENT *comp;
480 481 482
    LPCWSTR clsid;
    LPCWSTR context;
    LPCWSTR buffer;
483
    MSIPACKAGE* package = param;
484
    MSICLASS *cls;
485 486 487 488 489
    BOOL match = FALSE;

    clsid = MSI_RecordGetString(rec,1);
    context = MSI_RecordGetString(rec,2);
    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 501 502 503
        {
            match = TRUE;
            break;
        }
    }
504

505 506 507 508 509 510
    if (!match)
        load_class(package, rec);

    return ERROR_SUCCESS;
}

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 521

    rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
    msiobj_release(&view->hdr);
522
    return rc;
523 524 525 526
}

static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
{
527
    MSICOMPONENT *comp;
528 529
    LPCWSTR buffer;
    LPCWSTR extension;
530
    MSIPACKAGE* package = param;
531
    BOOL match = FALSE;
532
    MSIEXTENSION *ext;
533 534 535

    extension = MSI_RecordGetString(rec,1);
    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 545 546 547 548 549 550 551 552 553 554
        {
            match = TRUE;
            break;
        }
    }

    if (!match)
        load_extension(package, rec);

    return ERROR_SUCCESS;
}

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 565

    rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
    msiobj_release(&view->hdr);
566
    return rc;
567 568 569 570 571
}

static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
{
    LPCWSTR buffer;
572
    MSIPACKAGE* package = param;
573 574 575 576 577 578

    buffer = MSI_RecordGetString(rec,1);
    load_given_progid(package,buffer);
    return ERROR_SUCCESS;
}

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 589

    rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
    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 603

    rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
    msiobj_release(&view->hdr);
604
    return rc;
605 606 607 608 609
}

static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
{
    LPCWSTR buffer;
610
    MSIPACKAGE* package = param;
611 612 613 614 615 616

    buffer = MSI_RecordGetString(rec,1);
    load_given_mime(package,buffer);
    return ERROR_SUCCESS;
}

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 627

    rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
    msiobj_release(&view->hdr);
628
    return rc;
629 630
}

631
static UINT load_classes_and_such( MSIPACKAGE *package )
632
{
633 634
    UINT r;

635 636 637
    TRACE("Loading all the class info and related tables\n");

    /* check if already loaded */
638
    if (!list_empty( &package->classes ) ||
639 640
        !list_empty( &package->mimes ) ||
        !list_empty( &package->extensions ) ||
641 642 643 644 645 646 647 648 649 650
        !list_empty( &package->progids )) return ERROR_SUCCESS;

    r = load_all_classes( package );
    if (r != ERROR_SUCCESS) return r;

    r = load_all_extensions( package );
    if (r != ERROR_SUCCESS) return r;

    r = load_all_progids( package );
    if (r != ERROR_SUCCESS) return r;
651 652

    /* these loads must come after the other loads */
653 654 655 656
    r = load_all_verbs( package );
    if (r != ERROR_SUCCESS) return r;

    return load_all_mimes( package );
657 658
}

659
static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
660
{
661 662 663
    HKEY hkey2, hkey3;

    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 687 688 689 690 691

    RegCloseKey(hkey3);
    return ERROR_SUCCESS;
}

UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
{
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 702 703
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
704

705 706
    if (package->platform == PLATFORM_INTEL)
        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 712
        return ERROR_FUNCTION_FAILED;

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 724
            continue;

725 726 727 728 729 730
        if (!comp->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

731
        feature = cls->Feature;
732 733
        if (!feature)
            continue;
734

735 736 737
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_LOCAL &&
            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 742 743
            continue;
        }

744
        if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
745 746 747 748
        {
            TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
            continue;
        }
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 762 763 764 765
        /*
         * FIXME: Implement install on demand (advertised components).
         *
         * ole32.dll should call msi.MsiProvideComponentFromDescriptor()
         *  when it needs an InProcServer that doesn't exist.
         * The component advertise string should be in the "InProcServer" value.
766
         */
767 768 769
        size = lstrlenW( file->TargetPath )+1;
        if (cls->Argument)
            size += lstrlenW(cls->Argument)+1;
770

771 772
        argument = msi_alloc( size * sizeof(WCHAR) );
        lstrcpyW( argument, file->TargetPath );
773

774
        if (cls->Argument)
775
        {
776
            lstrcatW( argument, L" " );
777
            lstrcatW( argument, cls->Argument );
778 779
        }

780 781 782
        msi_reg_set_val_str( hkey3, NULL, argument );
        msi_free(argument);

783 784
        RegCloseKey(hkey3);

785
        if (cls->ProgID || cls->ProgIDText)
786 787 788
        {
            LPCWSTR progid;

789 790
            if (cls->ProgID)
                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 819 820
        RegCloseKey(hkey2);

        /* if there is a FileTypeMask, register the FileType */
821
        if (cls->FileTypeMask)
822 823 824 825
        {
            LPWSTR ptr, ptr2;
            LPWSTR keyname;
            INT index = 0;
826
            ptr = cls->FileTypeMask;
827 828
            while (ptr && *ptr)
            {
829
                ptr2 = wcschr(ptr,';');
830 831
                if (ptr2)
                    *ptr2 = 0;
832 833 834
                keyname = msi_alloc( (lstrlenW(L"FileType\\%s\\%d") + lstrlenW(cls->clsid) + 4) * sizeof(WCHAR));
                swprintf( keyname, lstrlenW(L"FileType\\%s\\%d") + lstrlenW(cls->clsid) + 4,
                          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 840 841 842 843 844 845 846

                if (ptr2)
                    ptr = ptr2+1;
                else
                    ptr = NULL;

                index ++;
            }
        }
847

848
        uirow = MSI_CreateRecord(1);
849
        MSI_RecordSetStringW( uirow, 1, cls->clsid );
850
        MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
851 852 853
        msiobj_release(&uirow->hdr);
    }
    RegCloseKey(hkey);
854 855 856 857 858
    return ERROR_SUCCESS;
}

UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
{
859
    REGSAM access = KEY_ALL_ACCESS;
860 861 862
    MSIRECORD *uirow;
    MSICLASS *cls;
    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 869 870
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
871

872 873
    if (package->platform == PLATFORM_INTEL)
        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 881 882 883 884 885 886 887 888 889 890

    LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
    {
        MSIFEATURE *feature;
        MSICOMPONENT *comp;
        LPWSTR filetype;
        LONG res;

        comp = cls->Component;
        if (!comp)
            continue;

891 892 893 894 895 896
        if (!comp->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

897 898 899 900
        feature = cls->Feature;
        if (!feature)
            continue;

901 902
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_ABSENT)
903
        {
904
            TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n",
905 906 907 908 909
                  debugstr_w(feature->Feature), debugstr_w(cls->clsid));
            continue;
        }
        TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);

910
        cls->action = INSTALLSTATE_ABSENT;
911 912 913 914 915 916 917

        res = RegDeleteTreeW( hkey, cls->clsid );
        if (res != ERROR_SUCCESS)
            WARN("Failed to delete class key %d\n", res);

        if (cls->AppID)
        {
918
            res = RegOpenKeyW( HKEY_CLASSES_ROOT, L"AppID", &hkey2 );
919 920 921 922 923 924 925 926 927 928
            if (res == ERROR_SUCCESS)
            {
                res = RegDeleteKeyW( hkey2, cls->AppID->AppID );
                if (res != ERROR_SUCCESS)
                    WARN("Failed to delete appid key %d\n", res);
                RegCloseKey( hkey2 );
            }
        }
        if (cls->FileTypeMask)
        {
929
            filetype = msi_alloc( (lstrlenW( L"FileType\\" ) + lstrlenW( cls->clsid ) + 1) * sizeof(WCHAR) );
930 931
            if (filetype)
            {
932
                lstrcpyW( filetype, L"FileType\\" );
933
                lstrcatW( filetype, cls->clsid );
934 935 936 937 938 939 940 941 942 943
                res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype );
                msi_free( filetype );

                if (res != ERROR_SUCCESS)
                    WARN("Failed to delete file type %d\n", res);
            }
        }

        uirow = MSI_CreateRecord( 1 );
        MSI_RecordSetStringW( uirow, 1, cls->clsid );
944
        MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
945 946 947 948
        msiobj_release( &uirow->hdr );
    }
    RegCloseKey( hkey );
    return ERROR_SUCCESS;
949 950
}

951
static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid )
952
{
953
    while (progid)
954
    {
955 956
        if (progid->Class)
            return progid->Class->clsid;
957 958
        if (progid->Parent == progid)
            break;
959
        progid = progid->Parent;
960
    }
961
    return NULL;
962 963
}

964
static UINT register_progid( const MSIPROGID* progid )
965
{
966 967
    HKEY hkey = 0;
    UINT rc;
968

969 970
    rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
    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 990

        RegCloseKey(hkey);
    }
991 992 993
    else
        ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );

994 995 996
    return rc;
}

997 998 999 1000 1001 1002
static const MSICLASS *get_progid_class( const MSIPROGID *progid )
{
    while (progid)
    {
        if (progid->Parent) progid = progid->Parent;
        if (progid->Class) return progid->Class;
Vincent Povirk's avatar
Vincent Povirk committed
1003
        if (!progid->Parent || progid->Parent == progid) break;
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
    }
    return NULL;
}

static BOOL has_class_installed( const MSIPROGID *progid )
{
    const MSICLASS *class = get_progid_class( progid );
    if (!class || !class->ProgID) return FALSE;
    return (class->action == INSTALLSTATE_LOCAL);
}

static BOOL has_one_extension_installed( const MSIPACKAGE *package, const MSIPROGID *progid )
{
    const MSIEXTENSION *extension;
    LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
    {
        if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
            extension->action == INSTALLSTATE_LOCAL) return TRUE;
    }
    return FALSE;
}

1026 1027
UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
{
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 1036 1037
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        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 1045
            continue;
        }
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 1056 1057
    }
    return ERROR_SUCCESS;
}

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
static BOOL has_class_removed( const MSIPROGID *progid )
{
    const MSICLASS *class = get_progid_class( progid );
    if (!class || !class->ProgID) return FALSE;
    return (class->action == INSTALLSTATE_ABSENT);
}

static BOOL has_extensions( const MSIPACKAGE *package, const MSIPROGID *progid )
{
    const MSIEXTENSION *extension;
    LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
    {
        if (extension->ProgID == progid && !list_empty( &extension->verbs )) return TRUE;
    }
    return FALSE;
}

static BOOL has_all_extensions_removed( const MSIPACKAGE *package, const MSIPROGID *progid )
{
    BOOL ret = FALSE;
    const MSIEXTENSION *extension;
    LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
    {
        if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
            extension->action == INSTALLSTATE_ABSENT) ret = TRUE;
        else ret = FALSE;
    }
    return ret;
}

1088 1089 1090 1091 1092
UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
{
    MSIPROGID *progid;
    MSIRECORD *uirow;
    LONG res;
1093
    UINT r;
1094

1095
    if (package->script == SCRIPT_NONE)
1096
        return msi_schedule_action( package, SCRIPT_INSTALL, L"UnregisterProgIdInfo" );
1097

1098 1099 1100
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1101 1102 1103

    LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
    {
1104 1105
        if (!has_class_removed( progid ) ||
            (has_extensions( package, progid ) && !has_all_extensions_removed( package, progid )))
1106 1107 1108 1109 1110 1111 1112 1113
        {
            TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
            continue;
        }
        TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));

        res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
        if (res != ERROR_SUCCESS)
1114
            TRACE("Failed to delete progid key %d\n", res);
1115 1116 1117

        uirow = MSI_CreateRecord( 1 );
        MSI_RecordSetStringW( uirow, 1, progid->ProgID );
1118
        MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1119 1120 1121 1122 1123
        msiobj_release( &uirow->hdr );
    }
    return ERROR_SUCCESS;
}

1124
static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
1125
                MSICOMPONENT* component, const MSIEXTENSION* extension,
1126 1127 1128 1129 1130 1131 1132 1133
                MSIVERB* verb, INT* Sequence )
{
    LPWSTR keyname;
    HKEY key;
    LPWSTR command;
    DWORD size;
    LPWSTR advertise;

1134
    keyname = msi_build_directory_name(4, progid, L"shell", verb->Verb, L"command");
1135 1136 1137

    TRACE("Making Key %s\n",debugstr_w(keyname));
    RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1138
    size = lstrlenW(component->FullKeypath);
1139
    if (verb->Argument)
1140
        size += lstrlenW(verb->Argument);
1141 1142
     size += 4;

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 1153
     advertise = msi_create_component_advertise_string(package, component,
                                                       extension->Feature->Feature);
1154
     size = lstrlenW(advertise);
1155 1156

     if (verb->Argument)
1157
         size += lstrlenW(verb->Argument);
1158 1159
     size += 4;

1160
     command = msi_alloc_zero(size * sizeof (WCHAR));
1161

1162
     lstrcpyW(command,advertise);
1163 1164
     if (verb->Argument)
     {
1165 1166
         lstrcatW(command, L" ");
         lstrcatW(command, verb->Argument);
1167 1168
     }

1169 1170
     msi_reg_set_val_multi_str( key, L"command", command );

1171
     RegCloseKey(key);
1172 1173 1174
     msi_free(keyname);
     msi_free(advertise);
     msi_free(command);
1175 1176 1177

     if (verb->Command)
     {
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 1184 1185 1186 1187
     }

     if (verb->Sequence != MSI_NULL_INTEGER)
     {
        if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
        {
            *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 1194 1195 1196 1197
        }
    }
    return ERROR_SUCCESS;
}

UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
{
1198
    HKEY hkey = NULL;
1199
    MSIEXTENSION *ext;
1200 1201
    MSIRECORD *uirow;
    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 1209 1210
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1211 1212 1213 1214 1215

    /* We need to set install_on_demand based on if the shell handles advertised
     * shortcuts and the like. Because Mike McCormack is working on this i am
     * going to default to TRUE
     */
1216

1217
    LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
1218
    {
1219
        LPWSTR extension;
1220
        MSIFEATURE *feature;
1221

1222
        if (!ext->Component)
1223 1224
            continue;

1225 1226 1227 1228 1229 1230
        if (!ext->Component->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

1231
        feature = ext->Feature;
1232 1233
        if (!feature)
            continue;
1234

1235
        /*
1236 1237 1238
         * yes. MSDN says that these are based on _Feature_ not on
         * Component.  So verify the feature is to be installed
         */
1239 1240 1241
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_LOCAL &&
            !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED))
1242
        {
1243 1244
            TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n",
                  debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1245 1246
            continue;
        }
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 1253 1254
        if (extension)
        {
            extension[0] = '.';
1255
            lstrcpyW( extension + 1, ext->Extension );
1256 1257 1258 1259 1260
            res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey );
            msi_free( extension );
            if (res != ERROR_SUCCESS)
                WARN("Failed to create extension key %d\n", res);
        }
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 1268 1269
        {
            HKEY hkey2;
            LPWSTR newkey;
            LPCWSTR progid;
1270
            MSIVERB *verb;
1271
            INT Sequence = MSI_NULL_INTEGER;
1272

1273 1274
            if (ext->ProgID)
                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 1283 1284
            lstrcpyW(newkey, progid);
            lstrcatW(newkey, L"\\ShellNew");
            RegCreateKeyW(hkey, newkey, &hkey2);
1285 1286
            RegCloseKey(hkey2);

1287
            msi_free(newkey);
1288 1289

            /* do all the verbs */
1290 1291
            LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry )
            {
1292
                register_verb( package, progid, ext->Component,
1293 1294
                               ext, verb, &Sequence);
            }
1295
        }
1296

1297 1298 1299
        RegCloseKey(hkey);

        uirow = MSI_CreateRecord(1);
1300
        MSI_RecordSetStringW( uirow, 1, ext->Extension );
1301
        MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1302 1303 1304 1305 1306
        msiobj_release(&uirow->hdr);
    }
    return ERROR_SUCCESS;
}

1307 1308 1309 1310 1311
UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
{
    MSIEXTENSION *ext;
    MSIRECORD *uirow;
    LONG res;
1312
    UINT r;
1313

1314
    if (package->script == SCRIPT_NONE)
1315
        return msi_schedule_action( package, SCRIPT_INSTALL, L"UnregisterExtensionInfo" );
1316

1317 1318 1319
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1320 1321 1322 1323 1324 1325 1326 1327 1328

    LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
    {
        LPWSTR extension;
        MSIFEATURE *feature;

        if (!ext->Component)
            continue;

1329 1330 1331 1332 1333 1334
        if (!ext->Component->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

1335 1336 1337 1338
        feature = ext->Feature;
        if (!feature)
            continue;

1339 1340
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_ABSENT)
1341
        {
1342 1343
            TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n",
                  debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1344 1345 1346 1347
            continue;
        }
        TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension));

1348
        ext->action = INSTALLSTATE_ABSENT;
1349

1350
        extension = msi_alloc( (lstrlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
1351 1352 1353
        if (extension)
        {
            extension[0] = '.';
1354
            lstrcpyW( extension + 1, ext->Extension );
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
            res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension );
            msi_free( extension );
            if (res != ERROR_SUCCESS)
                WARN("Failed to delete extension key %d\n", res);
        }

        if (ext->ProgID || ext->ProgIDText)
        {
            LPCWSTR progid;
            LPWSTR progid_shell;

            if (ext->ProgID)
                progid = ext->ProgID->ProgID;
            else
                progid = ext->ProgIDText;

1371
            progid_shell = msi_alloc( (lstrlenW( progid ) + lstrlenW( L"\\shell" ) + 1) * sizeof(WCHAR) );
1372 1373
            if (progid_shell)
            {
1374
                lstrcpyW( progid_shell, progid );
1375
                lstrcatW( progid_shell, L"\\shell" );
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
                res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell );
                msi_free( progid_shell );
                if (res != ERROR_SUCCESS)
                    WARN("Failed to delete shell key %d\n", res);
                RegDeleteKeyW( HKEY_CLASSES_ROOT, progid );
            }
        }

        uirow = MSI_CreateRecord( 1 );
        MSI_RecordSetStringW( uirow, 1, ext->Extension );
1386
        MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1387 1388 1389 1390 1391
        msiobj_release( &uirow->hdr );
    }
    return ERROR_SUCCESS;
}

1392 1393 1394
UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
{
    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 1402 1403
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1404

1405
    LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
1406
    {
1407
        LPWSTR extension = NULL, key;
1408

1409
        /*
Austin English's avatar
Austin English committed
1410
         * check if the MIME is to be installed. Either as requested by an
1411 1412
         * extension or Class
         */
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 1418
            continue;
        }
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 1424
        key = msi_alloc( (lstrlenW( mt->ContentType ) +
                          lstrlenW( L"MIME\\Database\\Content Type\\" ) + 1) * sizeof(WCHAR) );
1425

1426 1427 1428
        if (extension && key)
        {
            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 1439 1440 1441 1442
        }
        msi_free( extension );
        msi_free( key );

        uirow = MSI_CreateRecord( 2 );
        MSI_RecordSetStringW( uirow, 1, mt->ContentType );
1443
        MSI_RecordSetStringW( uirow, 2, mt->suffix );
1444
        MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1445 1446 1447 1448 1449 1450 1451 1452 1453
        msiobj_release( &uirow->hdr );
    }
    return ERROR_SUCCESS;
}

UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
{
    MSIRECORD *uirow;
    MSIMIME *mime;
1454
    UINT r;
1455

1456
    if (package->script == SCRIPT_NONE)
1457
        return msi_schedule_action( package, SCRIPT_INSTALL, L"UnregisterMIMEInfo" );
1458

1459 1460 1461
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1462 1463 1464 1465 1466 1467

    LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry )
    {
        LONG res;
        LPWSTR mime_key;

1468
        if ((!mime->Class || mime->Class->action != INSTALLSTATE_ABSENT) &&
1469
            (!mime->Extension || mime->Extension->action != INSTALLSTATE_ABSENT))
1470 1471 1472 1473 1474 1475 1476
        {
            TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType));
            continue;
        }

        TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType));

1477 1478
        mime_key = msi_alloc( (lstrlenW( L"MIME\\Database\\Content Type\\" ) +
                               lstrlenW( mime->ContentType ) + 1) * sizeof(WCHAR) );
1479 1480
        if (mime_key)
        {
1481
            lstrcpyW( mime_key, L"MIME\\Database\\Content Type\\" );
1482
            lstrcatW( mime_key, mime->ContentType );
1483 1484 1485 1486 1487 1488 1489 1490
            res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key );
            if (res != ERROR_SUCCESS)
                WARN("Failed to delete MIME key %d\n", res);
            msi_free( mime_key );
        }

        uirow = MSI_CreateRecord( 2 );
        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 1496
    }
    return ERROR_SUCCESS;
}