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