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