ole32: Check buffer bounds when reading storage properties.
[wine.git] / dlls / msi / classes.c
blob4e0c1a68098dfacd31ef40baacbfa868fd783a78
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
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
21 /* Actions handled in this module:
23 * RegisterClassInfo
24 * RegisterProgIdInfo
25 * RegisterExtensionInfo
26 * RegisterMIMEInfo
27 * UnregisterClassInfo
28 * UnregisterProgIdInfo
29 * UnregisterExtensionInfo
30 * UnregisterMIMEInfo
33 #include <stdarg.h>
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"
43 WINE_DEFAULT_DEBUG_CHANNEL(msi);
45 static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row )
47 LPCWSTR buffer;
48 MSIAPPID *appid;
50 /* fill in the data */
52 appid = msi_alloc_zero( sizeof(MSIAPPID) );
53 if (!appid)
54 return NULL;
56 appid->AppID = msi_dup_record_field( row, 1 );
57 TRACE("loading appid %s\n", debugstr_w( appid->AppID ));
59 buffer = MSI_RecordGetString(row,2);
60 deformat_string( package, buffer, &appid->RemoteServerName );
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);
66 appid->ActivateAtStorage = !MSI_RecordIsNull(row,6);
67 appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
69 list_add_tail( &package->appids, &appid->entry );
71 return appid;
74 static MSIAPPID *load_given_appid( MSIPACKAGE *package, LPCWSTR name )
76 static const WCHAR query[] = {
77 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
78 '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
79 '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
80 MSIRECORD *row;
81 MSIAPPID *appid;
83 if (!name)
84 return NULL;
86 /* check for appids already loaded */
87 LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry )
89 if (!wcsicmp( appid->AppID, name ))
91 TRACE("found appid %s %p\n", debugstr_w(name), appid);
92 return appid;
96 row = MSI_QueryGetRecord(package->db, query, name);
97 if (!row)
98 return NULL;
100 appid = load_appid(package, row);
101 msiobj_release(&row->hdr);
102 return appid;
105 static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
106 static MSICLASS *load_given_class( MSIPACKAGE *package, LPCWSTR classid );
108 static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
110 MSIPROGID *progid;
111 LPCWSTR buffer;
113 /* fill in the data */
115 progid = msi_alloc_zero( sizeof(MSIPROGID) );
116 if (!progid)
117 return NULL;
119 list_add_tail( &package->progids, &progid->entry );
121 progid->ProgID = msi_dup_record_field(row,1);
122 TRACE("loading progid %s\n",debugstr_w(progid->ProgID));
124 buffer = MSI_RecordGetString(row,2);
125 progid->Parent = load_given_progid(package,buffer);
126 if (progid->Parent == NULL && buffer)
127 FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
129 buffer = MSI_RecordGetString(row,3);
130 progid->Class = load_given_class(package,buffer);
131 if (progid->Class == NULL && buffer)
132 FIXME("Unknown class %s\n",debugstr_w(buffer));
134 progid->Description = msi_dup_record_field(row,4);
136 if (!MSI_RecordIsNull(row,6))
138 INT icon_index = MSI_RecordGetInteger(row,6);
139 LPCWSTR FileName = MSI_RecordGetString(row,5);
140 LPWSTR FilePath;
141 static const WCHAR fmt[] = {'%','s',',','%','i',0};
143 FilePath = msi_build_icon_path(package, FileName);
145 progid->IconPath = msi_alloc( (lstrlenW(FilePath)+10)* sizeof(WCHAR) );
147 swprintf(progid->IconPath,lstrlenW(FilePath)+10,fmt,FilePath,icon_index);
149 msi_free(FilePath);
151 else
153 buffer = MSI_RecordGetString(row,5);
154 if (buffer)
155 progid->IconPath = msi_build_icon_path(package, buffer);
158 progid->CurVer = NULL;
159 progid->VersionInd = NULL;
161 /* if we have a parent then we may be that parents CurVer */
162 if (progid->Parent && progid->Parent != progid)
164 MSIPROGID *parent = progid->Parent;
166 while (parent->Parent && parent->Parent != parent)
167 parent = parent->Parent;
169 /* FIXME: need to determine if we are really the CurVer */
171 progid->CurVer = parent;
172 parent->VersionInd = progid;
175 return progid;
178 static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR name)
180 static const WCHAR query[] = {
181 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
182 '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
183 '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
184 MSIPROGID *progid;
185 MSIRECORD *row;
187 if (!name)
188 return NULL;
190 /* check for progids already loaded */
191 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
193 if (!wcsicmp( progid->ProgID, name ))
195 TRACE("found progid %s (%p)\n",debugstr_w(name), progid );
196 return progid;
200 row = MSI_QueryGetRecord( package->db, query, name );
201 if (!row)
202 return NULL;
204 progid = load_progid(package, row);
205 msiobj_release(&row->hdr);
206 return progid;
209 static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
211 MSICLASS *cls;
212 DWORD i;
213 LPCWSTR buffer;
215 /* fill in the data */
217 cls = msi_alloc_zero( sizeof(MSICLASS) );
218 if (!cls)
219 return NULL;
221 list_add_tail( &package->classes, &cls->entry );
223 cls->clsid = msi_dup_record_field( row, 1 );
224 TRACE("loading class %s\n",debugstr_w(cls->clsid));
225 cls->Context = msi_dup_record_field( row, 2 );
226 buffer = MSI_RecordGetString(row,3);
227 cls->Component = msi_get_loaded_component( package, buffer );
229 cls->ProgIDText = msi_dup_record_field(row,4);
230 cls->ProgID = load_given_progid(package, cls->ProgIDText);
232 cls->Description = msi_dup_record_field(row,5);
234 buffer = MSI_RecordGetString(row,6);
235 if (buffer)
236 cls->AppID = load_given_appid(package, buffer);
238 cls->FileTypeMask = msi_dup_record_field(row,7);
240 if (!MSI_RecordIsNull(row,9))
243 INT icon_index = MSI_RecordGetInteger(row,9);
244 LPCWSTR FileName = MSI_RecordGetString(row,8);
245 LPWSTR FilePath;
246 static const WCHAR fmt[] = {'%','s',',','%','i',0};
248 FilePath = msi_build_icon_path(package, FileName);
250 cls->IconPath = msi_alloc( (lstrlenW(FilePath)+5)* sizeof(WCHAR) );
252 swprintf(cls->IconPath,lstrlenW(FilePath)+5,fmt,FilePath,icon_index);
254 msi_free(FilePath);
256 else
258 buffer = MSI_RecordGetString(row,8);
259 if (buffer)
260 cls->IconPath = msi_build_icon_path(package, buffer);
263 if (!MSI_RecordIsNull(row,10))
265 i = MSI_RecordGetInteger(row,10);
266 if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
268 static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
269 static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
271 switch(i)
273 case 1:
274 cls->DefInprocHandler = strdupW(ole2);
275 break;
276 case 2:
277 cls->DefInprocHandler32 = strdupW(ole32);
278 break;
279 case 3:
280 cls->DefInprocHandler = strdupW(ole2);
281 cls->DefInprocHandler32 = strdupW(ole32);
282 break;
285 else
287 cls->DefInprocHandler32 = msi_dup_record_field( row, 10 );
288 msi_reduce_to_long_filename( cls->DefInprocHandler32 );
291 buffer = MSI_RecordGetString(row,11);
292 deformat_string(package,buffer,&cls->Argument);
294 buffer = MSI_RecordGetString(row,12);
295 cls->Feature = msi_get_loaded_feature(package, buffer);
297 cls->Attributes = MSI_RecordGetInteger(row,13);
298 cls->action = INSTALLSTATE_UNKNOWN;
299 return cls;
303 * the Class table has 3 primary keys. Generally it is only
304 * referenced through the first CLSID key. However when loading
305 * all of the classes we need to make sure we do not ignore rows
306 * with other Context and ComponentIndexs
308 static MSICLASS *load_given_class(MSIPACKAGE *package, LPCWSTR classid)
310 static const WCHAR query[] = {
311 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
312 '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
313 '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
314 MSICLASS *cls;
315 MSIRECORD *row;
317 if (!classid)
318 return NULL;
320 /* check for classes already loaded */
321 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
323 if (!wcsicmp( cls->clsid, classid ))
325 TRACE("found class %s (%p)\n",debugstr_w(classid), cls);
326 return cls;
330 row = MSI_QueryGetRecord(package->db, query, classid);
331 if (!row)
332 return NULL;
334 cls = load_class(package, row);
335 msiobj_release(&row->hdr);
336 return cls;
339 static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR extension );
341 static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row )
343 LPCWSTR extension;
344 MSIMIME *mt;
346 /* fill in the data */
348 mt = msi_alloc_zero( sizeof(MSIMIME) );
349 if (!mt)
350 return mt;
352 mt->ContentType = msi_dup_record_field( row, 1 );
353 TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
355 extension = MSI_RecordGetString( row, 2 );
356 mt->Extension = load_given_extension( package, extension );
357 mt->suffix = strdupW( extension );
359 mt->clsid = msi_dup_record_field( row, 3 );
360 mt->Class = load_given_class( package, mt->clsid );
362 list_add_tail( &package->mimes, &mt->entry );
364 return mt;
367 static MSIMIME *load_given_mime( MSIPACKAGE *package, LPCWSTR mime )
369 static const WCHAR query[] = {
370 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
371 '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
372 '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ','\'','%','s','\'',0};
373 MSIRECORD *row;
374 MSIMIME *mt;
376 if (!mime)
377 return NULL;
379 /* check for mime already loaded */
380 LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
382 if (!wcsicmp( mt->ContentType, mime ))
384 TRACE("found mime %s (%p)\n",debugstr_w(mime), mt);
385 return mt;
389 row = MSI_QueryGetRecord(package->db, query, mime);
390 if (!row)
391 return NULL;
393 mt = load_mime(package, row);
394 msiobj_release(&row->hdr);
395 return mt;
398 static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row )
400 MSIEXTENSION *ext;
401 LPCWSTR buffer;
403 /* fill in the data */
405 ext = msi_alloc_zero( sizeof(MSIEXTENSION) );
406 if (!ext)
407 return NULL;
409 list_init( &ext->verbs );
411 list_add_tail( &package->extensions, &ext->entry );
413 ext->Extension = msi_dup_record_field( row, 1 );
414 TRACE("loading extension %s\n", debugstr_w(ext->Extension));
416 buffer = MSI_RecordGetString( row, 2 );
417 ext->Component = msi_get_loaded_component( package, buffer );
419 ext->ProgIDText = msi_dup_record_field( row, 3 );
420 ext->ProgID = load_given_progid( package, ext->ProgIDText );
422 buffer = MSI_RecordGetString( row, 4 );
423 ext->Mime = load_given_mime( package, buffer );
425 buffer = MSI_RecordGetString(row,5);
426 ext->Feature = msi_get_loaded_feature( package, buffer );
427 ext->action = INSTALLSTATE_UNKNOWN;
428 return ext;
432 * While the extension table has 2 primary keys, this function is only looking
433 * at the Extension key which is what is referenced as a foreign key
435 static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR name )
437 static const WCHAR query[] = {
438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
439 '`','E','x','t','e','n','s','i','o','n','`',' ','W','H','E','R','E',' ',
440 '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
441 MSIEXTENSION *ext;
442 MSIRECORD *row;
444 if (!name)
445 return NULL;
447 if (name[0] == '.')
448 name++;
450 /* check for extensions already loaded */
451 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
453 if (!wcsicmp( ext->Extension, name ))
455 TRACE("extension %s already loaded %p\n", debugstr_w(name), ext);
456 return ext;
460 row = MSI_QueryGetRecord( package->db, query, name );
461 if (!row)
462 return NULL;
464 ext = load_extension(package, row);
465 msiobj_release(&row->hdr);
466 return ext;
469 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
471 MSIPACKAGE* package = param;
472 MSIVERB *verb;
473 LPCWSTR buffer;
474 MSIEXTENSION *extension;
476 buffer = MSI_RecordGetString(row,1);
477 extension = load_given_extension( package, buffer );
478 if (!extension)
480 ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
481 return ERROR_SUCCESS;
484 /* fill in the data */
486 verb = msi_alloc_zero( sizeof(MSIVERB) );
487 if (!verb)
488 return ERROR_OUTOFMEMORY;
490 verb->Verb = msi_dup_record_field(row,2);
491 TRACE("loading verb %s\n",debugstr_w(verb->Verb));
492 verb->Sequence = MSI_RecordGetInteger(row,3);
494 buffer = MSI_RecordGetString(row,4);
495 deformat_string(package,buffer,&verb->Command);
497 buffer = MSI_RecordGetString(row,5);
498 deformat_string(package,buffer,&verb->Argument);
500 /* associate the verb with the correct extension */
501 list_add_tail( &extension->verbs, &verb->entry );
503 return ERROR_SUCCESS;
506 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
508 MSICOMPONENT *comp;
509 LPCWSTR clsid;
510 LPCWSTR context;
511 LPCWSTR buffer;
512 MSIPACKAGE* package = param;
513 MSICLASS *cls;
514 BOOL match = FALSE;
516 clsid = MSI_RecordGetString(rec,1);
517 context = MSI_RecordGetString(rec,2);
518 buffer = MSI_RecordGetString(rec,3);
519 comp = msi_get_loaded_component(package, buffer);
521 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
523 if (wcsicmp( clsid, cls->clsid ))
524 continue;
525 if (wcscmp( context, cls->Context ))
526 continue;
527 if (comp == cls->Component)
529 match = TRUE;
530 break;
534 if (!match)
535 load_class(package, rec);
537 return ERROR_SUCCESS;
540 static UINT load_all_classes( MSIPACKAGE *package )
542 static const WCHAR query[] = {
543 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','C','l','a','s','s','`',0};
544 MSIQUERY *view;
545 UINT rc;
547 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
548 if (rc != ERROR_SUCCESS)
549 return ERROR_SUCCESS;
551 rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
552 msiobj_release(&view->hdr);
553 return rc;
556 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
558 MSICOMPONENT *comp;
559 LPCWSTR buffer;
560 LPCWSTR extension;
561 MSIPACKAGE* package = param;
562 BOOL match = FALSE;
563 MSIEXTENSION *ext;
565 extension = MSI_RecordGetString(rec,1);
566 buffer = MSI_RecordGetString(rec,2);
567 comp = msi_get_loaded_component(package, buffer);
569 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
571 if (wcsicmp(extension, ext->Extension))
572 continue;
573 if (comp == ext->Component)
575 match = TRUE;
576 break;
580 if (!match)
581 load_extension(package, rec);
583 return ERROR_SUCCESS;
586 static UINT load_all_extensions( MSIPACKAGE *package )
588 static const WCHAR query[] = {
589 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','E','x','t','e','n','s','i','o','n','`',0};
590 MSIQUERY *view;
591 UINT rc;
593 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
594 if (rc != ERROR_SUCCESS)
595 return ERROR_SUCCESS;
597 rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
598 msiobj_release(&view->hdr);
599 return rc;
602 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
604 LPCWSTR buffer;
605 MSIPACKAGE* package = param;
607 buffer = MSI_RecordGetString(rec,1);
608 load_given_progid(package,buffer);
609 return ERROR_SUCCESS;
612 static UINT load_all_progids( MSIPACKAGE *package )
614 static const WCHAR query[] = {
615 'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ','F','R','O','M',' ',
616 '`','P','r','o','g','I','d','`',0};
617 MSIQUERY *view;
618 UINT rc;
620 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
621 if (rc != ERROR_SUCCESS)
622 return ERROR_SUCCESS;
624 rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
625 msiobj_release(&view->hdr);
626 return rc;
629 static UINT load_all_verbs( MSIPACKAGE *package )
631 static const WCHAR query[] = {
632 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','V','e','r','b','`',0};
633 MSIQUERY *view;
634 UINT rc;
636 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
637 if (rc != ERROR_SUCCESS)
638 return ERROR_SUCCESS;
640 rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
641 msiobj_release(&view->hdr);
642 return rc;
645 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
647 LPCWSTR buffer;
648 MSIPACKAGE* package = param;
650 buffer = MSI_RecordGetString(rec,1);
651 load_given_mime(package,buffer);
652 return ERROR_SUCCESS;
655 static UINT load_all_mimes( MSIPACKAGE *package )
657 static const WCHAR query[] = {
658 'S','E','L','E','C','T',' ','`','C','o','n','t','e','n','t','T','y','p','e','`',' ',
659 'F','R','O','M',' ','`','M','I','M','E','`',0};
660 MSIQUERY *view;
661 UINT rc;
663 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
664 if (rc != ERROR_SUCCESS)
665 return ERROR_SUCCESS;
667 rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
668 msiobj_release(&view->hdr);
669 return rc;
672 static UINT load_classes_and_such( MSIPACKAGE *package )
674 UINT r;
676 TRACE("Loading all the class info and related tables\n");
678 /* check if already loaded */
679 if (!list_empty( &package->classes ) ||
680 !list_empty( &package->mimes ) ||
681 !list_empty( &package->extensions ) ||
682 !list_empty( &package->progids )) return ERROR_SUCCESS;
684 r = load_all_classes( package );
685 if (r != ERROR_SUCCESS) return r;
687 r = load_all_extensions( package );
688 if (r != ERROR_SUCCESS) return r;
690 r = load_all_progids( package );
691 if (r != ERROR_SUCCESS) return r;
693 /* these loads must come after the other loads */
694 r = load_all_verbs( package );
695 if (r != ERROR_SUCCESS) return r;
697 return load_all_mimes( package );
700 static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
702 static const WCHAR szRemoteServerName[] =
703 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
704 static const WCHAR szLocalService[] =
705 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
706 static const WCHAR szService[] =
707 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
708 static const WCHAR szDLL[] =
709 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
710 static const WCHAR szActivate[] =
711 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
712 static const WCHAR szY[] = {'Y',0};
713 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
714 static const WCHAR szUser[] =
715 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
717 HKEY hkey2,hkey3;
719 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
720 RegCreateKeyW( hkey2, appid->AppID, &hkey3 );
721 RegCloseKey(hkey2);
722 msi_reg_set_val_str( hkey3, NULL, app );
724 if (appid->RemoteServerName)
725 msi_reg_set_val_str( hkey3, szRemoteServerName, appid->RemoteServerName );
727 if (appid->LocalServer)
728 msi_reg_set_val_str( hkey3, szLocalService, appid->LocalServer );
730 if (appid->ServiceParameters)
731 msi_reg_set_val_str( hkey3, szService, appid->ServiceParameters );
733 if (appid->DllSurrogate)
734 msi_reg_set_val_str( hkey3, szDLL, appid->DllSurrogate );
736 if (appid->ActivateAtStorage)
737 msi_reg_set_val_str( hkey3, szActivate, szY );
739 if (appid->RunAsInteractiveUser)
740 msi_reg_set_val_str( hkey3, szRunAs, szUser );
742 RegCloseKey(hkey3);
743 return ERROR_SUCCESS;
746 UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
748 static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
749 REGSAM access = KEY_ALL_ACCESS;
750 MSIRECORD *uirow;
751 HKEY hkey, hkey2, hkey3;
752 MSICLASS *cls;
753 UINT r;
755 if (package->script == SCRIPT_NONE)
756 return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterClassInfo);
758 r = load_classes_and_such( package );
759 if (r != ERROR_SUCCESS)
760 return r;
762 if (package->platform == PLATFORM_INTEL)
763 access |= KEY_WOW64_32KEY;
764 else
765 access |= KEY_WOW64_64KEY;
767 if (RegCreateKeyExW( HKEY_CLASSES_ROOT, szCLSID, 0, NULL, 0, access, NULL, &hkey, NULL ))
768 return ERROR_FUNCTION_FAILED;
770 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
772 MSICOMPONENT *comp;
773 MSIFILE *file;
774 DWORD size;
775 LPWSTR argument;
776 MSIFEATURE *feature;
778 comp = cls->Component;
779 if ( !comp )
780 continue;
782 if (!comp->Enabled)
784 TRACE("component is disabled\n");
785 continue;
788 feature = cls->Feature;
789 if (!feature)
790 continue;
792 feature->Action = msi_get_feature_action( package, feature );
793 if (feature->Action != INSTALLSTATE_LOCAL &&
794 feature->Action != INSTALLSTATE_ADVERTISED )
796 TRACE("feature %s not scheduled for installation, skipping registration of class %s\n",
797 debugstr_w(feature->Feature), debugstr_w(cls->clsid));
798 continue;
801 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
803 TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
804 continue;
806 TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
808 cls->action = INSTALLSTATE_LOCAL;
810 RegCreateKeyW( hkey, cls->clsid, &hkey2 );
812 if (cls->Description)
813 msi_reg_set_val_str( hkey2, NULL, cls->Description );
815 RegCreateKeyW( hkey2, cls->Context, &hkey3 );
818 * FIXME: Implement install on demand (advertised components).
820 * ole32.dll should call msi.MsiProvideComponentFromDescriptor()
821 * when it needs an InProcServer that doesn't exist.
822 * The component advertise string should be in the "InProcServer" value.
824 size = lstrlenW( file->TargetPath )+1;
825 if (cls->Argument)
826 size += lstrlenW(cls->Argument)+1;
828 argument = msi_alloc( size * sizeof(WCHAR) );
829 lstrcpyW( argument, file->TargetPath );
831 if (cls->Argument)
833 lstrcatW( argument, szSpace );
834 lstrcatW( argument, cls->Argument );
837 msi_reg_set_val_str( hkey3, NULL, argument );
838 msi_free(argument);
840 RegCloseKey(hkey3);
842 if (cls->ProgID || cls->ProgIDText)
844 LPCWSTR progid;
846 if (cls->ProgID)
847 progid = cls->ProgID->ProgID;
848 else
849 progid = cls->ProgIDText;
851 msi_reg_set_subkey_val( hkey2, szProgID, NULL, progid );
853 if (cls->ProgID && cls->ProgID->VersionInd)
855 msi_reg_set_subkey_val( hkey2, szVIProgID, NULL,
856 cls->ProgID->VersionInd->ProgID );
860 if (cls->AppID)
862 MSIAPPID *appid = cls->AppID;
863 msi_reg_set_val_str( hkey2, szAppID, appid->AppID );
864 register_appid( appid, cls->Description );
867 if (cls->IconPath)
868 msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath );
870 if (cls->DefInprocHandler)
871 msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler );
873 if (cls->DefInprocHandler32)
874 msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 );
875 RegCloseKey(hkey2);
877 /* if there is a FileTypeMask, register the FileType */
878 if (cls->FileTypeMask)
880 LPWSTR ptr, ptr2;
881 LPWSTR keyname;
882 INT index = 0;
883 ptr = cls->FileTypeMask;
884 while (ptr && *ptr)
886 ptr2 = wcschr(ptr,';');
887 if (ptr2)
888 *ptr2 = 0;
889 keyname = msi_alloc( (lstrlenW(szFileType_fmt) + lstrlenW(cls->clsid) + 4) * sizeof(WCHAR));
890 swprintf( keyname, lstrlenW(szFileType_fmt) + lstrlenW(cls->clsid) + 4,
891 szFileType_fmt, cls->clsid, index );
893 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, ptr );
894 msi_free(keyname);
896 if (ptr2)
897 ptr = ptr2+1;
898 else
899 ptr = NULL;
901 index ++;
905 uirow = MSI_CreateRecord(1);
906 MSI_RecordSetStringW( uirow, 1, cls->clsid );
907 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
908 msiobj_release(&uirow->hdr);
910 RegCloseKey(hkey);
911 return ERROR_SUCCESS;
914 UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
916 static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0};
917 REGSAM access = KEY_ALL_ACCESS;
918 MSIRECORD *uirow;
919 MSICLASS *cls;
920 HKEY hkey, hkey2;
921 UINT r;
923 if (package->script == SCRIPT_NONE)
924 return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterClassInfo);
926 r = load_classes_and_such( package );
927 if (r != ERROR_SUCCESS)
928 return r;
930 if (package->platform == PLATFORM_INTEL)
931 access |= KEY_WOW64_32KEY;
932 else
933 access |= KEY_WOW64_64KEY;
935 if (RegCreateKeyExW( HKEY_CLASSES_ROOT, szCLSID, 0, NULL, 0, access, NULL, &hkey, NULL ))
936 return ERROR_FUNCTION_FAILED;
938 LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
940 MSIFEATURE *feature;
941 MSICOMPONENT *comp;
942 LPWSTR filetype;
943 LONG res;
945 comp = cls->Component;
946 if (!comp)
947 continue;
949 if (!comp->Enabled)
951 TRACE("component is disabled\n");
952 continue;
955 feature = cls->Feature;
956 if (!feature)
957 continue;
959 feature->Action = msi_get_feature_action( package, feature );
960 if (feature->Action != INSTALLSTATE_ABSENT)
962 TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n",
963 debugstr_w(feature->Feature), debugstr_w(cls->clsid));
964 continue;
966 TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);
968 cls->action = INSTALLSTATE_ABSENT;
970 res = RegDeleteTreeW( hkey, cls->clsid );
971 if (res != ERROR_SUCCESS)
972 WARN("Failed to delete class key %d\n", res);
974 if (cls->AppID)
976 res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 );
977 if (res == ERROR_SUCCESS)
979 res = RegDeleteKeyW( hkey2, cls->AppID->AppID );
980 if (res != ERROR_SUCCESS)
981 WARN("Failed to delete appid key %d\n", res);
982 RegCloseKey( hkey2 );
985 if (cls->FileTypeMask)
987 filetype = msi_alloc( (lstrlenW( szFileType ) + lstrlenW( cls->clsid ) + 1) * sizeof(WCHAR) );
988 if (filetype)
990 lstrcpyW( filetype, szFileType );
991 lstrcatW( filetype, cls->clsid );
992 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype );
993 msi_free( filetype );
995 if (res != ERROR_SUCCESS)
996 WARN("Failed to delete file type %d\n", res);
1000 uirow = MSI_CreateRecord( 1 );
1001 MSI_RecordSetStringW( uirow, 1, cls->clsid );
1002 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1003 msiobj_release( &uirow->hdr );
1005 RegCloseKey( hkey );
1006 return ERROR_SUCCESS;
1009 static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid )
1011 while (progid)
1013 if (progid->Class)
1014 return progid->Class->clsid;
1015 if (progid->Parent == progid)
1016 break;
1017 progid = progid->Parent;
1019 return NULL;
1022 static UINT register_progid( const MSIPROGID* progid )
1024 static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0};
1025 HKEY hkey = 0;
1026 UINT rc;
1028 rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
1029 if (rc == ERROR_SUCCESS)
1031 LPCWSTR clsid = get_clsid_of_progid( progid );
1033 if (clsid)
1034 msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
1035 else
1036 TRACE("%s has no class\n", debugstr_w( progid->ProgID ) );
1038 if (progid->Description)
1039 msi_reg_set_val_str( hkey, NULL, progid->Description );
1041 if (progid->IconPath)
1042 msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath );
1044 /* write out the current version */
1045 if (progid->CurVer)
1046 msi_reg_set_subkey_val( hkey, szCurVer, NULL, progid->CurVer->ProgID );
1048 RegCloseKey(hkey);
1050 else
1051 ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );
1053 return rc;
1056 static const MSICLASS *get_progid_class( const MSIPROGID *progid )
1058 while (progid)
1060 if (progid->Parent) progid = progid->Parent;
1061 if (progid->Class) return progid->Class;
1062 if (!progid->Parent || progid->Parent == progid) break;
1064 return NULL;
1067 static BOOL has_class_installed( const MSIPROGID *progid )
1069 const MSICLASS *class = get_progid_class( progid );
1070 if (!class || !class->ProgID) return FALSE;
1071 return (class->action == INSTALLSTATE_LOCAL);
1074 static BOOL has_one_extension_installed( const MSIPACKAGE *package, const MSIPROGID *progid )
1076 const MSIEXTENSION *extension;
1077 LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
1079 if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
1080 extension->action == INSTALLSTATE_LOCAL) return TRUE;
1082 return FALSE;
1085 UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
1087 MSIPROGID *progid;
1088 MSIRECORD *uirow;
1089 UINT r;
1091 if (package->script == SCRIPT_NONE)
1092 return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterProgIdInfo);
1094 r = load_classes_and_such( package );
1095 if (r != ERROR_SUCCESS)
1096 return r;
1098 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
1100 if (!has_class_installed( progid ) && !has_one_extension_installed( package, progid ))
1102 TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid->ProgID));
1103 continue;
1105 TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
1107 register_progid( progid );
1109 uirow = MSI_CreateRecord( 1 );
1110 MSI_RecordSetStringW( uirow, 1, progid->ProgID );
1111 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1112 msiobj_release( &uirow->hdr );
1114 return ERROR_SUCCESS;
1117 static BOOL has_class_removed( const MSIPROGID *progid )
1119 const MSICLASS *class = get_progid_class( progid );
1120 if (!class || !class->ProgID) return FALSE;
1121 return (class->action == INSTALLSTATE_ABSENT);
1124 static BOOL has_extensions( const MSIPACKAGE *package, const MSIPROGID *progid )
1126 const MSIEXTENSION *extension;
1127 LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
1129 if (extension->ProgID == progid && !list_empty( &extension->verbs )) return TRUE;
1131 return FALSE;
1134 static BOOL has_all_extensions_removed( const MSIPACKAGE *package, const MSIPROGID *progid )
1136 BOOL ret = FALSE;
1137 const MSIEXTENSION *extension;
1138 LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
1140 if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
1141 extension->action == INSTALLSTATE_ABSENT) ret = TRUE;
1142 else ret = FALSE;
1144 return ret;
1147 UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
1149 MSIPROGID *progid;
1150 MSIRECORD *uirow;
1151 LONG res;
1152 UINT r;
1154 if (package->script == SCRIPT_NONE)
1155 return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterProgIdInfo);
1157 r = load_classes_and_such( package );
1158 if (r != ERROR_SUCCESS)
1159 return r;
1161 LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
1163 if (!has_class_removed( progid ) ||
1164 (has_extensions( package, progid ) && !has_all_extensions_removed( package, progid )))
1166 TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
1167 continue;
1169 TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
1171 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
1172 if (res != ERROR_SUCCESS)
1173 TRACE("Failed to delete progid key %d\n", res);
1175 uirow = MSI_CreateRecord( 1 );
1176 MSI_RecordSetStringW( uirow, 1, progid->ProgID );
1177 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1178 msiobj_release( &uirow->hdr );
1180 return ERROR_SUCCESS;
1183 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
1184 MSICOMPONENT* component, const MSIEXTENSION* extension,
1185 MSIVERB* verb, INT* Sequence )
1187 LPWSTR keyname;
1188 HKEY key;
1189 static const WCHAR szShell[] = {'s','h','e','l','l',0};
1190 static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
1191 static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
1192 static const WCHAR fmt2[] = {'\"','%','s','\"',0};
1193 LPWSTR command;
1194 DWORD size;
1195 LPWSTR advertise;
1197 keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand);
1199 TRACE("Making Key %s\n",debugstr_w(keyname));
1200 RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1201 size = lstrlenW(component->FullKeypath);
1202 if (verb->Argument)
1203 size += lstrlenW(verb->Argument);
1204 size += 4;
1206 command = msi_alloc(size * sizeof (WCHAR));
1207 if (verb->Argument)
1208 swprintf(command, size, fmt, component->FullKeypath, verb->Argument);
1209 else
1210 swprintf(command, size, fmt2, component->FullKeypath);
1212 msi_reg_set_val_str( key, NULL, command );
1213 msi_free(command);
1215 advertise = msi_create_component_advertise_string(package, component,
1216 extension->Feature->Feature);
1217 size = lstrlenW(advertise);
1219 if (verb->Argument)
1220 size += lstrlenW(verb->Argument);
1221 size += 4;
1223 command = msi_alloc_zero(size * sizeof (WCHAR));
1225 lstrcpyW(command,advertise);
1226 if (verb->Argument)
1228 lstrcatW(command,szSpace);
1229 lstrcatW(command,verb->Argument);
1232 msi_reg_set_val_multi_str( key, szCommand, command );
1234 RegCloseKey(key);
1235 msi_free(keyname);
1236 msi_free(advertise);
1237 msi_free(command);
1239 if (verb->Command)
1241 keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb );
1242 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command );
1243 msi_free(keyname);
1246 if (verb->Sequence != MSI_NULL_INTEGER)
1248 if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
1250 *Sequence = verb->Sequence;
1251 keyname = msi_build_directory_name( 2, progid, szShell );
1252 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb );
1253 msi_free(keyname);
1256 return ERROR_SUCCESS;
1259 UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
1261 static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0};
1262 HKEY hkey = NULL;
1263 MSIEXTENSION *ext;
1264 MSIRECORD *uirow;
1265 BOOL install_on_demand = TRUE;
1266 LONG res;
1267 UINT r;
1269 if (package->script == SCRIPT_NONE)
1270 return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterExtensionInfo);
1272 r = load_classes_and_such( package );
1273 if (r != ERROR_SUCCESS)
1274 return r;
1276 /* We need to set install_on_demand based on if the shell handles advertised
1277 * shortcuts and the like. Because Mike McCormack is working on this i am
1278 * going to default to TRUE
1281 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
1283 LPWSTR extension;
1284 MSIFEATURE *feature;
1286 if (!ext->Component)
1287 continue;
1289 if (!ext->Component->Enabled)
1291 TRACE("component is disabled\n");
1292 continue;
1295 feature = ext->Feature;
1296 if (!feature)
1297 continue;
1300 * yes. MSDN says that these are based on _Feature_ not on
1301 * Component. So verify the feature is to be installed
1303 feature->Action = msi_get_feature_action( package, feature );
1304 if (feature->Action != INSTALLSTATE_LOCAL &&
1305 !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED))
1307 TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n",
1308 debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1309 continue;
1311 TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext);
1313 ext->action = INSTALLSTATE_LOCAL;
1315 extension = msi_alloc( (lstrlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
1316 if (extension)
1318 extension[0] = '.';
1319 lstrcpyW( extension + 1, ext->Extension );
1320 res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey );
1321 msi_free( extension );
1322 if (res != ERROR_SUCCESS)
1323 WARN("Failed to create extension key %d\n", res);
1326 if (ext->Mime)
1327 msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType );
1329 if (ext->ProgID || ext->ProgIDText)
1331 static const WCHAR szSN[] =
1332 {'\\','S','h','e','l','l','N','e','w',0};
1333 HKEY hkey2;
1334 LPWSTR newkey;
1335 LPCWSTR progid;
1336 MSIVERB *verb;
1337 INT Sequence = MSI_NULL_INTEGER;
1339 if (ext->ProgID)
1340 progid = ext->ProgID->ProgID;
1341 else
1342 progid = ext->ProgIDText;
1344 msi_reg_set_val_str( hkey, NULL, progid );
1346 newkey = msi_alloc( (lstrlenW(progid)+lstrlenW(szSN)+1) * sizeof(WCHAR));
1348 lstrcpyW(newkey,progid);
1349 lstrcatW(newkey,szSN);
1350 RegCreateKeyW(hkey,newkey,&hkey2);
1351 RegCloseKey(hkey2);
1353 msi_free(newkey);
1355 /* do all the verbs */
1356 LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry )
1358 register_verb( package, progid, ext->Component,
1359 ext, verb, &Sequence);
1363 RegCloseKey(hkey);
1365 uirow = MSI_CreateRecord(1);
1366 MSI_RecordSetStringW( uirow, 1, ext->Extension );
1367 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1368 msiobj_release(&uirow->hdr);
1370 return ERROR_SUCCESS;
1373 UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
1375 MSIEXTENSION *ext;
1376 MSIRECORD *uirow;
1377 LONG res;
1378 UINT r;
1380 if (package->script == SCRIPT_NONE)
1381 return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterExtensionInfo);
1383 r = load_classes_and_such( package );
1384 if (r != ERROR_SUCCESS)
1385 return r;
1387 LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
1389 LPWSTR extension;
1390 MSIFEATURE *feature;
1392 if (!ext->Component)
1393 continue;
1395 if (!ext->Component->Enabled)
1397 TRACE("component is disabled\n");
1398 continue;
1401 feature = ext->Feature;
1402 if (!feature)
1403 continue;
1405 feature->Action = msi_get_feature_action( package, feature );
1406 if (feature->Action != INSTALLSTATE_ABSENT)
1408 TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n",
1409 debugstr_w(feature->Feature), debugstr_w(ext->Extension));
1410 continue;
1412 TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension));
1414 ext->action = INSTALLSTATE_ABSENT;
1416 extension = msi_alloc( (lstrlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
1417 if (extension)
1419 extension[0] = '.';
1420 lstrcpyW( extension + 1, ext->Extension );
1421 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension );
1422 msi_free( extension );
1423 if (res != ERROR_SUCCESS)
1424 WARN("Failed to delete extension key %d\n", res);
1427 if (ext->ProgID || ext->ProgIDText)
1429 static const WCHAR shellW[] = {'\\','s','h','e','l','l',0};
1430 LPCWSTR progid;
1431 LPWSTR progid_shell;
1433 if (ext->ProgID)
1434 progid = ext->ProgID->ProgID;
1435 else
1436 progid = ext->ProgIDText;
1438 progid_shell = msi_alloc( (lstrlenW( progid ) + lstrlenW( shellW ) + 1) * sizeof(WCHAR) );
1439 if (progid_shell)
1441 lstrcpyW( progid_shell, progid );
1442 lstrcatW( progid_shell, shellW );
1443 res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell );
1444 msi_free( progid_shell );
1445 if (res != ERROR_SUCCESS)
1446 WARN("Failed to delete shell key %d\n", res);
1447 RegDeleteKeyW( HKEY_CLASSES_ROOT, progid );
1451 uirow = MSI_CreateRecord( 1 );
1452 MSI_RecordSetStringW( uirow, 1, ext->Extension );
1453 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1454 msiobj_release( &uirow->hdr );
1456 return ERROR_SUCCESS;
1459 UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
1461 static const WCHAR szExtension[] = {'E','x','t','e','n','s','i','o','n',0};
1462 MSIRECORD *uirow;
1463 MSIMIME *mt;
1464 UINT r;
1466 if (package->script == SCRIPT_NONE)
1467 return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterMIMEInfo);
1469 r = load_classes_and_such( package );
1470 if (r != ERROR_SUCCESS)
1471 return r;
1473 LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
1475 LPWSTR extension = NULL, key;
1478 * check if the MIME is to be installed. Either as requested by an
1479 * extension or Class
1481 if ((!mt->Class || mt->Class->action != INSTALLSTATE_LOCAL) &&
1482 (!mt->Extension || mt->Extension->action != INSTALLSTATE_LOCAL))
1484 TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType));
1485 continue;
1488 TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType));
1490 if (mt->Extension) extension = msi_alloc( (lstrlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) );
1491 key = msi_alloc( (lstrlenW( mt->ContentType ) + lstrlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) );
1493 if (extension && key)
1495 extension[0] = '.';
1496 lstrcpyW( extension + 1, mt->Extension->Extension );
1498 lstrcpyW( key, szMIMEDatabase );
1499 lstrcatW( key, mt->ContentType );
1500 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExtension, extension );
1502 if (mt->clsid)
1503 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid );
1505 msi_free( extension );
1506 msi_free( key );
1508 uirow = MSI_CreateRecord( 2 );
1509 MSI_RecordSetStringW( uirow, 1, mt->ContentType );
1510 MSI_RecordSetStringW( uirow, 2, mt->suffix );
1511 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1512 msiobj_release( &uirow->hdr );
1514 return ERROR_SUCCESS;
1517 UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
1519 MSIRECORD *uirow;
1520 MSIMIME *mime;
1521 UINT r;
1523 if (package->script == SCRIPT_NONE)
1524 return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterMIMEInfo);
1526 r = load_classes_and_such( package );
1527 if (r != ERROR_SUCCESS)
1528 return r;
1530 LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry )
1532 LONG res;
1533 LPWSTR mime_key;
1535 if ((!mime->Class || mime->Class->action != INSTALLSTATE_ABSENT) &&
1536 (!mime->Extension || mime->Extension->action != INSTALLSTATE_ABSENT))
1538 TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType));
1539 continue;
1542 TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType));
1544 mime_key = msi_alloc( (lstrlenW( szMIMEDatabase ) + lstrlenW( mime->ContentType ) + 1) * sizeof(WCHAR) );
1545 if (mime_key)
1547 lstrcpyW( mime_key, szMIMEDatabase );
1548 lstrcatW( mime_key, mime->ContentType );
1549 res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key );
1550 if (res != ERROR_SUCCESS)
1551 WARN("Failed to delete MIME key %d\n", res);
1552 msi_free( mime_key );
1555 uirow = MSI_CreateRecord( 2 );
1556 MSI_RecordSetStringW( uirow, 1, mime->ContentType );
1557 MSI_RecordSetStringW( uirow, 2, mime->suffix );
1558 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
1559 msiobj_release( &uirow->hdr );
1561 return ERROR_SUCCESS;