classes.c 44.8 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 45
 */

#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"
#include "wine/unicode.h"

WINE_DEFAULT_DEBUG_CHANNEL(msi);

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

    /* fill in the data */

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

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

    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 78 79 80
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
        '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
81
    MSIRECORD *row;
82
    MSIAPPID *appid;
83

84 85
    if (!name)
        return NULL;
86 87

    /* check for appids already loaded */
88 89
    LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry )
    {
90
        if (!strcmpiW( appid->AppID, name ))
91
        {
92 93
            TRACE("found appid %s %p\n", debugstr_w(name), appid);
            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 113 114 115
    LPCWSTR buffer;

    /* fill in the data */

116
    progid = msi_alloc_zero( sizeof(MSIPROGID) );
117 118
    if (!progid)
        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 127
    progid->Parent = load_given_progid(package,buffer);
    if (progid->Parent == NULL && buffer)
128 129 130
        FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));

    buffer = MSI_RecordGetString(row,3);
131 132
    progid->Class = load_given_class(package,buffer);
    if (progid->Class == NULL && buffer)
133 134
        FIXME("Unknown class %s\n",debugstr_w(buffer));

135
    progid->Description = msi_dup_record_field(row,4);
136 137 138 139

    if (!MSI_RecordIsNull(row,6))
    {
        INT icon_index = MSI_RecordGetInteger(row,6); 
140
        LPCWSTR FileName = MSI_RecordGetString(row,5);
141 142 143
        LPWSTR FilePath;
        static const WCHAR fmt[] = {'%','s',',','%','i',0};

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 153 154 155
    }
    else
    {
        buffer = MSI_RecordGetString(row,5);
        if (buffer)
156
            progid->IconPath = msi_build_icon_path(package, buffer);
157 158
    }

159 160
    progid->CurVer = NULL;
    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 166
        MSIPROGID *parent = progid->Parent;

167
        while (parent->Parent && parent->Parent != parent)
168
            parent = parent->Parent;
169

Austin English's avatar
Austin English committed
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 182 183 184
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
        '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
185
    MSIPROGID *progid;
186 187
    MSIRECORD *row;

188 189
    if (!name)
        return NULL;
190 191

    /* check for progids already loaded */
192 193
    LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
    {
194
        if (!strcmpiW( progid->ProgID, name ))
195
        {
196 197
            TRACE("found progid %s (%p)\n",debugstr_w(name), progid );
            return progid;
198
        }
199
    }
200
    
201
    row = MSI_QueryGetRecord( package->db, query, name );
202 203
    if (!row)
        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 215 216 217
    LPCWSTR buffer;

    /* fill in the data */

218
    cls = msi_alloc_zero( sizeof(MSICLASS) );
219 220
    if (!cls)
        return NULL;
221

222 223
    list_add_tail( &package->classes, &cls->entry );

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 236

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

239
    cls->FileTypeMask = msi_dup_record_field(row,7);
240 241 242 243 244

    if (!MSI_RecordIsNull(row,9))
    {

        INT icon_index = MSI_RecordGetInteger(row,9); 
245
        LPCWSTR FileName = MSI_RecordGetString(row,8);
246 247 248
        LPWSTR FilePath;
        static const WCHAR fmt[] = {'%','s',',','%','i',0};

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 258 259 260
    }
    else
    {
        buffer = MSI_RecordGetString(row,8);
        if (buffer)
261
            cls->IconPath = msi_build_icon_path(package, buffer);
262 263 264 265 266 267 268 269 270 271 272 273 274
    }

    if (!MSI_RecordIsNull(row,10))
    {
        i = MSI_RecordGetInteger(row,10);
        if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
        {
            static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
            static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};

            switch(i)
            {
                case 1:
275
                    cls->DefInprocHandler = strdupW(ole2);
276 277
                    break;
                case 2:
278
                    cls->DefInprocHandler32 = strdupW(ole32);
279 280
                    break;
                case 3:
281 282
                    cls->DefInprocHandler = strdupW(ole2);
                    cls->DefInprocHandler32 = strdupW(ole32);
283 284 285 286 287
                    break;
            }
        }
        else
        {
288 289
            cls->DefInprocHandler32 = msi_dup_record_field( row, 10 );
            msi_reduce_to_long_filename( cls->DefInprocHandler32 );
290 291 292
        }
    }
    buffer = MSI_RecordGetString(row,11);
293
    deformat_string(package,buffer,&cls->Argument);
294 295

    buffer = MSI_RecordGetString(row,12);
296
    cls->Feature = msi_get_loaded_feature(package, buffer);
297

298
    cls->Attributes = MSI_RecordGetInteger(row,13);
299
    
300
    return cls;
301 302 303 304 305 306 307 308
}

/*
 * the Class table has 3 primary keys. Generally it is only 
 * referenced through the first CLSID key. However when loading
 * all of the classes we need to make sure we do not ignore rows
 * with other Context and ComponentIndexs 
 */
309
static MSICLASS *load_given_class(MSIPACKAGE *package, LPCWSTR classid)
310
{
311 312 313 314
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
        '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
315
    MSICLASS *cls;
316 317 318
    MSIRECORD *row;

    if (!classid)
319
        return NULL;
320 321
    
    /* check for classes already loaded */
322 323
    LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
    {
324
        if (!strcmpiW( cls->clsid, classid ))
325
        {
326 327
            TRACE("found class %s (%p)\n",debugstr_w(classid), cls);
            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 348

    /* fill in the data */

349
    mt = msi_alloc_zero( sizeof(MSIMIME) );
350 351
    if (!mt)
        return mt;
352

353
    mt->ContentType = msi_dup_record_field( row, 1 ); 
354
    TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
355

356 357 358
    extension = MSI_RecordGetString( row, 2 );
    mt->Extension = load_given_extension( package, extension );
    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 371 372 373
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
        '`','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 382
    LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
    {
383
        if (!strcmpiW( mt->ContentType, mime ))
384
        {
385 386
            TRACE("found mime %s (%p)\n",debugstr_w(mime), mt);
            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 403 404 405
    LPCWSTR buffer;

    /* fill in the data */

406
    ext = msi_alloc_zero( sizeof(MSIEXTENSION) );
407 408 409
    if (!ext)
        return NULL;

410 411
    list_init( &ext->verbs );

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 424
    buffer = MSI_RecordGetString( row, 4 );
    ext->Mime = load_given_mime( package, buffer );
425 426

    buffer = MSI_RecordGetString(row,5);
427
    ext->Feature = msi_get_loaded_feature( package, buffer );
428

429
    return ext;
430 431 432 433
}

/*
 * While the extension table has 2 primary keys, this function is only looking
Austin English's avatar
Austin English committed
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 439 440 441
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','E','x','t','e','n','s','i','o','n','`',' ','W','H','E','R','E',' ',
        '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
442
    MSIEXTENSION *ext;
443
    MSIRECORD *row;
444

445 446
    if (!name)
        return NULL;
447

448 449 450
    if (name[0] == '.')
        name++;

451
    /* check for extensions already loaded */
452 453
    LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
    {
454
        if (!strcmpiW( ext->Extension, name ))
455
        {
456 457
            TRACE("extension %s already loaded %p\n", debugstr_w(name), ext);
            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 471
}

static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
{
472
    MSIPACKAGE* package = param;
473
    MSIVERB *verb;
474
    LPCWSTR buffer;
475
    MSIEXTENSION *extension;
476 477

    buffer = MSI_RecordGetString(row,1);
478 479 480
    extension = load_given_extension( package, buffer );
    if (!extension)
    {
481
        ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
482 483 484 485
        return ERROR_SUCCESS;
    }

    /* fill in the data */
486

487
    verb = msi_alloc_zero( sizeof(MSIVERB) );
488 489 490
    if (!verb)
        return ERROR_OUTOFMEMORY;

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

Austin English's avatar
Austin English committed
501
    /* associate the verb with the correct extension */
502
    list_add_tail( &extension->verbs, &verb->entry );
503 504 505 506 507 508
    
    return ERROR_SUCCESS;
}

static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
{
509
    MSICOMPONENT *comp;
510 511 512
    LPCWSTR clsid;
    LPCWSTR context;
    LPCWSTR buffer;
513
    MSIPACKAGE* package = param;
514
    MSICLASS *cls;
515 516 517 518 519
    BOOL match = FALSE;

    clsid = MSI_RecordGetString(rec,1);
    context = MSI_RecordGetString(rec,2);
    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 531 532 533 534 535 536 537 538 539 540
        {
            match = TRUE;
            break;
        }
    }
    
    if (!match)
        load_class(package, rec);

    return ERROR_SUCCESS;
}

541
static UINT load_all_classes( MSIPACKAGE *package )
542
{
543 544
    static const WCHAR query[] = {
        '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 553

    rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
    msiobj_release(&view->hdr);
554
    return rc;
555 556 557 558
}

static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
{
559
    MSICOMPONENT *comp;
560 561
    LPCWSTR buffer;
    LPCWSTR extension;
562
    MSIPACKAGE* package = param;
563
    BOOL match = FALSE;
564
    MSIEXTENSION *ext;
565 566 567

    extension = MSI_RecordGetString(rec,1);
    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 577 578 579 580 581 582 583 584 585 586
        {
            match = TRUE;
            break;
        }
    }

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

    return ERROR_SUCCESS;
}

587
static UINT load_all_extensions( MSIPACKAGE *package )
588
{
589 590
    static const WCHAR query[] = {
        '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 599

    rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
    msiobj_release(&view->hdr);
600
    return rc;
601 602 603 604 605
}

static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
{
    LPCWSTR buffer;
606
    MSIPACKAGE* package = param;
607 608 609 610 611 612

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

613
static UINT load_all_progids( MSIPACKAGE *package )
614
{
615 616 617
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ','F','R','O','M',' ',
        '`','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 626

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

630
static UINT load_all_verbs( MSIPACKAGE *package )
631
{
632 633
    static const WCHAR query[] = {
        '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 642

    rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
    msiobj_release(&view->hdr);
643
    return rc;
644 645 646 647 648
}

static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
{
    LPCWSTR buffer;
649
    MSIPACKAGE* package = param;
650 651 652 653 654 655

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

656
static UINT load_all_mimes( MSIPACKAGE *package )
657
{
658 659 660
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','`','C','o','n','t','e','n','t','T','y','p','e','`',' ',
        '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 669

    rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
    msiobj_release(&view->hdr);
670
    return rc;
671 672
}

673
static UINT load_classes_and_such( MSIPACKAGE *package )
674
{
675 676
    UINT r;

677 678 679
    TRACE("Loading all the class info and related tables\n");

    /* check if already loaded */
680
    if (!list_empty( &package->classes ) ||
681 682
        !list_empty( &package->mimes ) ||
        !list_empty( &package->extensions ) ||
683 684 685 686 687 688 689 690 691 692
        !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;
693 694

    /* these loads must come after the other loads */
695 696 697 698
    r = load_all_verbs( package );
    if (r != ERROR_SUCCESS) return r;

    return load_all_mimes( package );
699 700
}

701
static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid )
702
{
703
    MSIPROGID *child;
704

705
    if (!progid)
706 707
        return;

708
    if (progid->InstallMe)
709 710 711 712 713
        return;

    progid->InstallMe = TRUE;

    /* all children if this is a parent also install */
714 715 716 717 718
    LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry )
    {
        if (child->Parent == progid)
            mark_progid_for_install( package, child );
    }
719 720
}

721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
static void mark_progid_for_uninstall( MSIPACKAGE *package, MSIPROGID *progid )
{
    MSIPROGID *child;

    if (!progid)
        return;

    if (!progid->InstallMe)
        return;

    progid->InstallMe = FALSE;

    LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry )
    {
        if (child->Parent == progid)
            mark_progid_for_uninstall( package, child );
    }
}

740
static void mark_mime_for_install( MSIMIME *mime )
741
{
742
    if (!mime)
743 744 745 746
        return;
    mime->InstallMe = TRUE;
}

747 748 749 750 751 752 753
static void mark_mime_for_uninstall( MSIMIME *mime )
{
    if (!mime)
        return;
    mime->InstallMe = FALSE;
}

754
static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
755
{
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
    static const WCHAR szRemoteServerName[] =
         {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
    static const WCHAR szLocalService[] =
         {'L','o','c','a','l','S','e','r','v','i','c','e',0};
    static const WCHAR szService[] =
         {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
    static const WCHAR szDLL[] =
         {'D','l','l','S','u','r','r','o','g','a','t','e',0};
    static const WCHAR szActivate[] =
         {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
    static const WCHAR szY[] = {'Y',0};
    static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
    static const WCHAR szUser[] = 
         {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};

771 772 773
    HKEY hkey2,hkey3;

    RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
774
    RegCreateKeyW( hkey2, appid->AppID, &hkey3 );
775
    RegCloseKey(hkey2);
776
    msi_reg_set_val_str( hkey3, NULL, app );
777

778
    if (appid->RemoteServerName)
779
        msi_reg_set_val_str( hkey3, szRemoteServerName, appid->RemoteServerName );
780

781
    if (appid->LocalServer)
782
        msi_reg_set_val_str( hkey3, szLocalService, appid->LocalServer );
783

784
    if (appid->ServiceParameters)
785
        msi_reg_set_val_str( hkey3, szService, appid->ServiceParameters );
786

787
    if (appid->DllSurrogate)
788
        msi_reg_set_val_str( hkey3, szDLL, appid->DllSurrogate );
789

790
    if (appid->ActivateAtStorage)
791
        msi_reg_set_val_str( hkey3, szActivate, szY );
792

793
    if (appid->RunAsInteractiveUser)
794
        msi_reg_set_val_str( hkey3, szRunAs, szUser );
795 796 797 798 799 800 801 802

    RegCloseKey(hkey3);
    return ERROR_SUCCESS;
}

UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
{
    static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
803
    const WCHAR *keypath;
804
    MSIRECORD *uirow;
805
    HKEY hkey, hkey2, hkey3;
806
    MSICLASS *cls;
807
    UINT r;
808

809 810 811
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
812 813 814 815 816 817 818

    if (is_64bit && package->platform == PLATFORM_INTEL)
        keypath = szWow6432NodeCLSID;
    else
        keypath = szCLSID;

    if (RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, &hkey) != ERROR_SUCCESS)
819 820
        return ERROR_FUNCTION_FAILED;

821
    LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
822
    {
823
        MSICOMPONENT *comp;
824
        MSIFILE *file;
825
        DWORD size;
826
        LPWSTR argument;
827
        MSIFEATURE *feature;
828

829
        comp = cls->Component;
830
        if ( !comp )
831 832
            continue;

833 834 835 836 837 838
        if (!comp->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

839
        feature = cls->Feature;
840 841
        if (!feature)
            continue;
842

843 844 845
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_LOCAL &&
            feature->Action != INSTALLSTATE_ADVERTISED )
846
        {
847
            TRACE("feature %s not scheduled for installation, skipping registration of class %s\n",
848
                  debugstr_w(feature->Feature), debugstr_w(cls->clsid));
849 850 851
            continue;
        }

852
        if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
853 854 855 856
        {
            TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
            continue;
        }
857
        TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
858

859
        cls->Installed = TRUE;
860
        mark_progid_for_install( package, cls->ProgID );
861

862
        RegCreateKeyW( hkey, cls->clsid, &hkey2 );
863

864
        if (cls->Description)
865
            msi_reg_set_val_str( hkey2, NULL, cls->Description );
866

867
        RegCreateKeyW( hkey2, cls->Context, &hkey3 );
868

869 870 871 872 873 874
        /*
         * 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.
875
         */
876 877 878
        size = lstrlenW( file->TargetPath )+1;
        if (cls->Argument)
            size += lstrlenW(cls->Argument)+1;
879

880 881
        argument = msi_alloc( size * sizeof(WCHAR) );
        lstrcpyW( argument, file->TargetPath );
882

883
        if (cls->Argument)
884
        {
885 886
            lstrcatW( argument, szSpace );
            lstrcatW( argument, cls->Argument );
887 888
        }

889 890 891
        msi_reg_set_val_str( hkey3, NULL, argument );
        msi_free(argument);

892 893
        RegCloseKey(hkey3);

894
        if (cls->ProgID || cls->ProgIDText)
895 896 897
        {
            LPCWSTR progid;

898 899
            if (cls->ProgID)
                progid = cls->ProgID->ProgID;
900
            else
901
                progid = cls->ProgIDText;
902

903
            msi_reg_set_subkey_val( hkey2, szProgID, NULL, progid );
904

905
            if (cls->ProgID && cls->ProgID->VersionInd)
906
            {
907 908
                msi_reg_set_subkey_val( hkey2, szVIProgID, NULL, 
                                        cls->ProgID->VersionInd->ProgID );
909 910 911
            }
        }

912
        if (cls->AppID)
913
        {
914
            MSIAPPID *appid = cls->AppID;
915
            msi_reg_set_val_str( hkey2, szAppID, appid->AppID );
916
            register_appid( appid, cls->Description );
917 918
        }

919
        if (cls->IconPath)
920
            msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath );
921

922
        if (cls->DefInprocHandler)
923
            msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler );
924

925
        if (cls->DefInprocHandler32)
926
            msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 );
927 928 929 930
        
        RegCloseKey(hkey2);

        /* if there is a FileTypeMask, register the FileType */
931
        if (cls->FileTypeMask)
932 933 934 935
        {
            LPWSTR ptr, ptr2;
            LPWSTR keyname;
            INT index = 0;
936
            ptr = cls->FileTypeMask;
937 938 939 940 941
            while (ptr && *ptr)
            {
                ptr2 = strchrW(ptr,';');
                if (ptr2)
                    *ptr2 = 0;
942
                keyname = msi_alloc( (strlenW(szFileType_fmt) + strlenW(cls->clsid) + 4) * sizeof(WCHAR));
943
                sprintfW( keyname, szFileType_fmt, cls->clsid, index );
944

945
                msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, ptr );
946
                msi_free(keyname);
947 948 949 950 951 952 953 954 955 956 957

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

                index ++;
            }
        }
        
        uirow = MSI_CreateRecord(1);
958
        MSI_RecordSetStringW( uirow, 1, cls->clsid );
959
        msi_ui_actiondata( package, szRegisterClassInfo, uirow );
960 961 962
        msiobj_release(&uirow->hdr);
    }
    RegCloseKey(hkey);
963 964 965 966 967 968
    return ERROR_SUCCESS;
}

UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
{
    static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0};
969
    const WCHAR *keypath;
970 971 972
    MSIRECORD *uirow;
    MSICLASS *cls;
    HKEY hkey, hkey2;
973
    UINT r;
974

975 976 977
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
978 979 980 981 982 983 984

    if (is_64bit && package->platform == PLATFORM_INTEL)
        keypath = szWow6432NodeCLSID;
    else
        keypath = szCLSID;

    if (RegOpenKeyW( HKEY_CLASSES_ROOT, keypath, &hkey ) != ERROR_SUCCESS)
985 986 987 988 989 990 991 992 993 994 995 996 997
        return ERROR_SUCCESS;

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

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

998 999 1000 1001 1002 1003
        if (!comp->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

1004 1005 1006 1007
        feature = cls->Feature;
        if (!feature)
            continue;

1008 1009
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_ABSENT)
1010
        {
1011
            TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n",
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
                  debugstr_w(feature->Feature), debugstr_w(cls->clsid));
            continue;
        }
        TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);

        cls->Installed = FALSE;
        mark_progid_for_uninstall( package, cls->ProgID );

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

        if (cls->AppID)
        {
            res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 );
            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)
        {
            filetype = msi_alloc( (strlenW( szFileType ) + strlenW( cls->clsid ) + 1) * sizeof(WCHAR) );
            if (filetype)
            {
                strcpyW( filetype, szFileType );
                strcatW( filetype, cls->clsid );
                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 );
1052
        msi_ui_actiondata( package, szUnregisterClassInfo, uirow );
1053 1054 1055 1056
        msiobj_release( &uirow->hdr );
    }
    RegCloseKey( hkey );
    return ERROR_SUCCESS;
1057 1058
}

1059
static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid )
1060
{
1061
    while (progid)
1062
    {
1063 1064
        if (progid->Class)
            return progid->Class->clsid;
1065 1066
        if (progid->Parent == progid)
            break;
1067
        progid = progid->Parent;
1068
    }
1069
    return NULL;
1070 1071
}

1072
static UINT register_progid( const MSIPROGID* progid )
1073
{
1074
    static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0};
1075 1076
    HKEY hkey = 0;
    UINT rc;
1077

1078 1079
    rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
    if (rc == ERROR_SUCCESS)
1080
    {
1081
        LPCWSTR clsid = get_clsid_of_progid( progid );
1082

1083 1084 1085
        if (clsid)
            msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
        else
1086
            TRACE("%s has no class\n", debugstr_w( progid->ProgID ) );
1087 1088

        if (progid->Description)
1089
            msi_reg_set_val_str( hkey, NULL, progid->Description );
1090 1091

        if (progid->IconPath)
1092
            msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath );
1093 1094

        /* write out the current version */
1095
        if (progid->CurVer)
1096
            msi_reg_set_subkey_val( hkey, szCurVer, NULL, progid->CurVer->ProgID );
1097 1098 1099

        RegCloseKey(hkey);
    }
1100 1101 1102
    else
        ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );

1103 1104 1105 1106 1107
    return rc;
}

UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
{
1108
    MSIPROGID *progid;
1109
    MSIRECORD *uirow;
1110
    UINT r;
1111

1112 1113 1114
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1115

1116
    LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
1117 1118
    {
        /* check if this progid is to be installed */
1119 1120
        if (progid->Class && progid->Class->Installed)
            progid->InstallMe = TRUE;
1121

1122
        if (!progid->InstallMe)
1123 1124
        {
            TRACE("progid %s not scheduled to be installed\n",
1125
                             debugstr_w(progid->ProgID));
1126 1127 1128
            continue;
        }
       
1129
        TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
1130

1131
        register_progid( progid );
1132

1133
        uirow = MSI_CreateRecord( 1 );
1134
        MSI_RecordSetStringW( uirow, 1, progid->ProgID );
1135
        msi_ui_actiondata( package, szRegisterProgIdInfo, uirow );
1136
        msiobj_release( &uirow->hdr );
1137 1138 1139 1140
    }
    return ERROR_SUCCESS;
}

1141 1142 1143 1144 1145
UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
{
    MSIPROGID *progid;
    MSIRECORD *uirow;
    LONG res;
1146
    UINT r;
1147

1148 1149 1150
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167

    LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
    {
        /* check if this progid is to be removed */
        if (progid->Class && !progid->Class->Installed)
            progid->InstallMe = FALSE;

        if (progid->InstallMe)
        {
            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)
1168
            TRACE("Failed to delete progid key %d\n", res);
1169 1170 1171

        uirow = MSI_CreateRecord( 1 );
        MSI_RecordSetStringW( uirow, 1, progid->ProgID );
1172
        msi_ui_actiondata( package, szUnregisterProgIdInfo, uirow );
1173 1174 1175 1176 1177
        msiobj_release( &uirow->hdr );
    }
    return ERROR_SUCCESS;
}

1178
static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
1179
                MSICOMPONENT* component, const MSIEXTENSION* extension,
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
                MSIVERB* verb, INT* Sequence )
{
    LPWSTR keyname;
    HKEY key;
    static const WCHAR szShell[] = {'s','h','e','l','l',0};
    static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
    static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
    static const WCHAR fmt2[] = {'\"','%','s','\"',0};
    LPWSTR command;
    DWORD size;
    LPWSTR advertise;

1192
    keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand);
1193 1194 1195 1196 1197 1198 1199 1200

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

1201
     command = msi_alloc(size * sizeof (WCHAR));
1202 1203 1204 1205 1206
     if (verb->Argument)
        sprintfW(command, fmt, component->FullKeypath, verb->Argument);
     else
        sprintfW(command, fmt2, component->FullKeypath);

1207
     msi_reg_set_val_str( key, NULL, command );
1208
     msi_free(command);
1209

1210 1211
     advertise = msi_create_component_advertise_string(package, component,
                                                       extension->Feature->Feature);
1212 1213 1214
     size = strlenW(advertise);

     if (verb->Argument)
1215
         size += strlenW(verb->Argument);
1216 1217
     size += 4;

1218
     command = msi_alloc_zero(size * sizeof (WCHAR));
1219 1220 1221 1222 1223 1224 1225 1226

     strcpyW(command,advertise);
     if (verb->Argument)
     {
         strcatW(command,szSpace);
         strcatW(command,verb->Argument);
     }

1227
     msi_reg_set_val_multi_str( key, szCommand, command );
1228 1229
     
     RegCloseKey(key);
1230 1231 1232
     msi_free(keyname);
     msi_free(advertise);
     msi_free(command);
1233 1234 1235

     if (verb->Command)
     {
1236
        keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb );
1237
        msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command );
1238
        msi_free(keyname);
1239 1240 1241 1242 1243 1244 1245
     }

     if (verb->Sequence != MSI_NULL_INTEGER)
     {
        if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
        {
            *Sequence = verb->Sequence;
1246
            keyname = msi_build_directory_name( 2, progid, szShell );
1247
            msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb );
1248
            msi_free(keyname);
1249 1250 1251 1252 1253 1254 1255
        }
    }
    return ERROR_SUCCESS;
}

UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
{
1256
    static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0};
1257
    HKEY hkey = NULL;
1258
    MSIEXTENSION *ext;
1259 1260
    MSIRECORD *uirow;
    BOOL install_on_demand = TRUE;
1261
    LONG res;
1262
    UINT r;
1263

1264 1265 1266
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1267 1268 1269 1270 1271 1272

    /* 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
     */
    
1273
    LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
1274
    {
1275
        LPWSTR extension;
1276
        MSIFEATURE *feature;
1277
     
1278
        if (!ext->Component)
1279 1280
            continue;

1281 1282 1283 1284 1285 1286
        if (!ext->Component->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

1287
        feature = ext->Feature;
1288 1289
        if (!feature)
            continue;
1290

1291 1292 1293 1294
        /* 
         * yes. MSDN says that these are based on _Feature_ not on
         * Component.  So verify the feature is to be installed
         */
1295 1296 1297
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_LOCAL &&
            !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED))
1298
        {
1299 1300
            TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n",
                  debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1301 1302
            continue;
        }
1303
        TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext);
1304

1305
        ext->Installed = TRUE;
1306 1307 1308 1309

        /* this is only registered if the extension has at least 1 verb
         * according to MSDN
         */
1310 1311
        if (ext->ProgID && !list_empty( &ext->verbs ) )
            mark_progid_for_install( package, ext->ProgID );
1312

1313
        mark_mime_for_install(ext->Mime);
1314

1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
        extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
        if (extension)
        {
            extension[0] = '.';
            strcpyW( extension + 1, ext->Extension );
            res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey );
            msi_free( extension );
            if (res != ERROR_SUCCESS)
                WARN("Failed to create extension key %d\n", res);
        }
1325

1326
        if (ext->Mime)
1327
            msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType );
1328

1329
        if (ext->ProgID || ext->ProgIDText)
1330 1331 1332 1333 1334 1335
        {
            static const WCHAR szSN[] = 
                {'\\','S','h','e','l','l','N','e','w',0};
            HKEY hkey2;
            LPWSTR newkey;
            LPCWSTR progid;
1336
            MSIVERB *verb;
1337 1338
            INT Sequence = MSI_NULL_INTEGER;
            
1339 1340
            if (ext->ProgID)
                progid = ext->ProgID->ProgID;
1341
            else
1342
                progid = ext->ProgIDText;
1343

1344
            msi_reg_set_val_str( hkey, NULL, progid );
1345

1346
            newkey = msi_alloc( (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 
1347 1348 1349 1350 1351 1352

            strcpyW(newkey,progid);
            strcatW(newkey,szSN);
            RegCreateKeyW(hkey,newkey,&hkey2);
            RegCloseKey(hkey2);

1353
            msi_free(newkey);
1354 1355

            /* do all the verbs */
1356 1357
            LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry )
            {
1358
                register_verb( package, progid, ext->Component,
1359 1360
                               ext, verb, &Sequence);
            }
1361 1362 1363 1364 1365
        }
        
        RegCloseKey(hkey);

        uirow = MSI_CreateRecord(1);
1366
        MSI_RecordSetStringW( uirow, 1, ext->Extension );
1367
        msi_ui_actiondata( package, szRegisterExtensionInfo, uirow );
1368 1369 1370 1371 1372
        msiobj_release(&uirow->hdr);
    }
    return ERROR_SUCCESS;
}

1373 1374 1375 1376 1377
UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
{
    MSIEXTENSION *ext;
    MSIRECORD *uirow;
    LONG res;
1378
    UINT r;
1379

1380 1381 1382
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1383 1384 1385 1386 1387 1388 1389 1390 1391

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

        if (!ext->Component)
            continue;

1392 1393 1394 1395 1396 1397
        if (!ext->Component->Enabled)
        {
            TRACE("component is disabled\n");
            continue;
        }

1398 1399 1400 1401
        feature = ext->Feature;
        if (!feature)
            continue;

1402 1403
        feature->Action = msi_get_feature_action( package, feature );
        if (feature->Action != INSTALLSTATE_ABSENT)
1404
        {
1405 1406
            TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n",
                  debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
            continue;
        }
        TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension));

        ext->Installed = FALSE;

        if (ext->ProgID && !list_empty( &ext->verbs ))
            mark_progid_for_uninstall( package, ext->ProgID );

        mark_mime_for_uninstall( ext->Mime );

        extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
        if (extension)
        {
            extension[0] = '.';
            strcpyW( extension + 1, ext->Extension );
            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)
        {
            static const WCHAR shellW[] = {'\\','s','h','e','l','l',0};
            LPCWSTR progid;
            LPWSTR progid_shell;

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

            progid_shell = msi_alloc( (strlenW( progid ) + strlenW( shellW ) + 1) * sizeof(WCHAR) );
            if (progid_shell)
            {
                strcpyW( progid_shell, progid );
                strcatW( progid_shell, shellW );
                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 );
1455
        msi_ui_actiondata( package, szUnregisterExtensionInfo, uirow );
1456 1457 1458 1459 1460
        msiobj_release( &uirow->hdr );
    }
    return ERROR_SUCCESS;
}

1461 1462
UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
{
1463
    static const WCHAR szExtension[] = {'E','x','t','e','n','s','i','o','n',0};
1464
    MSIRECORD *uirow;
1465
    MSIMIME *mt;
1466
    UINT r;
1467

1468 1469 1470
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1471

1472
    LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
1473
    {
1474
        LPWSTR extension, key;
1475 1476

        /* 
Austin English's avatar
Austin English committed
1477
         * check if the MIME is to be installed. Either as requested by an
1478 1479
         * extension or Class
         */
1480 1481
        mt->InstallMe = (mt->InstallMe ||
              (mt->Class && mt->Class->Installed) ||
1482
              (mt->Extension && mt->Extension->Installed));
1483

1484
        if (!mt->InstallMe)
1485
        {
1486
            TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType));
1487 1488
            continue;
        }
1489

1490
        TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType));
1491

1492 1493
        extension = msi_alloc( (strlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) );
        key = msi_alloc( (strlenW( mt->ContentType ) + strlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) );
1494

1495 1496 1497 1498
        if (extension && key)
        {
            extension[0] = '.';
            strcpyW( extension + 1, mt->Extension->Extension );
1499

1500 1501
            strcpyW( key, szMIMEDatabase );
            strcatW( key, mt->ContentType );
1502
            msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExtension, extension );
1503

1504 1505 1506 1507 1508 1509 1510 1511
            if (mt->clsid)
                msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid );
        }
        msi_free( extension );
        msi_free( key );

        uirow = MSI_CreateRecord( 2 );
        MSI_RecordSetStringW( uirow, 1, mt->ContentType );
1512
        MSI_RecordSetStringW( uirow, 2, mt->suffix );
1513
        msi_ui_actiondata( package, szRegisterMIMEInfo, uirow );
1514 1515 1516 1517 1518 1519 1520 1521 1522
        msiobj_release( &uirow->hdr );
    }
    return ERROR_SUCCESS;
}

UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
{
    MSIRECORD *uirow;
    MSIMIME *mime;
1523
    UINT r;
1524

1525 1526 1527
    r = load_classes_and_such( package );
    if (r != ERROR_SUCCESS)
        return r;
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558

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

        mime->InstallMe = (mime->InstallMe ||
                          (mime->Class && mime->Class->Installed) ||
                          (mime->Extension && mime->Extension->Installed));

        if (mime->InstallMe)
        {
            TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType));
            continue;
        }

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

        mime_key = msi_alloc( (strlenW( szMIMEDatabase ) + strlenW( mime->ContentType ) + 1) * sizeof(WCHAR) );
        if (mime_key)
        {
            strcpyW( mime_key, szMIMEDatabase );
            strcatW( mime_key, mime->ContentType );
            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 );
1559
        MSI_RecordSetStringW( uirow, 2, mime->suffix );
1560
        msi_ui_actiondata( package, szUnregisterMIMEInfo, uirow );
1561
        msiobj_release( &uirow->hdr );
1562 1563 1564
    }
    return ERROR_SUCCESS;
}