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:
25 * RegisterExtensionInfo
28 * UnregisterProgIdInfo
29 * UnregisterExtensionInfo
39 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
45 static MSIAPPID
*load_appid( MSIPACKAGE
* package
, MSIRECORD
*row
)
50 /* fill in the data */
52 appid
= msi_alloc_zero( sizeof(MSIAPPID
) );
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
);
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};
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
);
96 row
= MSI_QueryGetRecord(package
->db
, query
, name
);
100 appid
= load_appid(package
, row
);
101 msiobj_release(&row
->hdr
);
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
)
113 /* fill in the data */
115 progid
= msi_alloc_zero( sizeof(MSIPROGID
) );
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);
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
);
153 buffer
= MSI_RecordGetString(row
,5);
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
;
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};
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
);
200 row
= MSI_QueryGetRecord( package
->db
, query
, name
);
204 progid
= load_progid(package
, row
);
205 msiobj_release(&row
->hdr
);
209 static MSICLASS
*load_class( MSIPACKAGE
* package
, MSIRECORD
*row
)
215 /* fill in the data */
217 cls
= msi_alloc_zero( sizeof(MSICLASS
) );
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);
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);
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
);
258 buffer
= MSI_RecordGetString(row
,8);
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};
274 cls
->DefInprocHandler
= strdupW(ole2
);
277 cls
->DefInprocHandler32
= strdupW(ole32
);
280 cls
->DefInprocHandler
= strdupW(ole2
);
281 cls
->DefInprocHandler32
= strdupW(ole32
);
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
;
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};
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
);
330 row
= MSI_QueryGetRecord(package
->db
, query
, classid
);
334 cls
= load_class(package
, row
);
335 msiobj_release(&row
->hdr
);
339 static MSIEXTENSION
*load_given_extension( MSIPACKAGE
*package
, LPCWSTR extension
);
341 static MSIMIME
*load_mime( MSIPACKAGE
* package
, MSIRECORD
*row
)
346 /* fill in the data */
348 mt
= msi_alloc_zero( sizeof(MSIMIME
) );
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
);
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};
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
);
389 row
= MSI_QueryGetRecord(package
->db
, query
, mime
);
393 mt
= load_mime(package
, row
);
394 msiobj_release(&row
->hdr
);
398 static MSIEXTENSION
*load_extension( MSIPACKAGE
* package
, MSIRECORD
*row
)
403 /* fill in the data */
405 ext
= msi_alloc_zero( sizeof(MSIEXTENSION
) );
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
;
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};
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
);
460 row
= MSI_QueryGetRecord( package
->db
, query
, name
);
464 ext
= load_extension(package
, row
);
465 msiobj_release(&row
->hdr
);
469 static UINT
iterate_load_verb(MSIRECORD
*row
, LPVOID param
)
471 MSIPACKAGE
* package
= param
;
474 MSIEXTENSION
*extension
;
476 buffer
= MSI_RecordGetString(row
,1);
477 extension
= load_given_extension( package
, buffer
);
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
) );
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
)
512 MSIPACKAGE
* package
= param
;
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
))
525 if (wcscmp( context
, cls
->Context
))
527 if (comp
== cls
->Component
)
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};
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
);
556 static UINT
iterate_all_extensions(MSIRECORD
*rec
, LPVOID param
)
561 MSIPACKAGE
* package
= param
;
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
))
573 if (comp
== ext
->Component
)
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};
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
);
602 static UINT
iterate_all_progids(MSIRECORD
*rec
, LPVOID param
)
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};
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
);
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};
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
);
645 static UINT
iterate_all_mimes(MSIRECORD
*rec
, LPVOID param
)
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};
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
);
672 static UINT
load_classes_and_such( MSIPACKAGE
*package
)
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};
719 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
720 RegCreateKeyW( hkey2
, appid
->AppID
, &hkey3
);
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
);
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
;
751 HKEY hkey
, hkey2
, hkey3
;
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
)
762 if (package
->platform
== PLATFORM_INTEL
)
763 access
|= KEY_WOW64_32KEY
;
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
)
778 comp
= cls
->Component
;
784 TRACE("component is disabled\n");
788 feature
= cls
->Feature
;
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
));
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
));
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;
826 size
+= lstrlenW(cls
->Argument
)+1;
828 argument
= msi_alloc( size
* sizeof(WCHAR
) );
829 lstrcpyW( argument
, file
->TargetPath
);
833 lstrcatW( argument
, szSpace
);
834 lstrcatW( argument
, cls
->Argument
);
837 msi_reg_set_val_str( hkey3
, NULL
, argument
);
842 if (cls
->ProgID
|| cls
->ProgIDText
)
847 progid
= cls
->ProgID
->ProgID
;
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
);
862 MSIAPPID
*appid
= cls
->AppID
;
863 msi_reg_set_val_str( hkey2
, szAppID
, appid
->AppID
);
864 register_appid( appid
, cls
->Description
);
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
);
877 /* if there is a FileTypeMask, register the FileType */
878 if (cls
->FileTypeMask
)
883 ptr
= cls
->FileTypeMask
;
886 ptr2
= wcschr(ptr
,';');
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
);
905 uirow
= MSI_CreateRecord(1);
906 MSI_RecordSetStringW( uirow
, 1, cls
->clsid
);
907 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, uirow
);
908 msiobj_release(&uirow
->hdr
);
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
;
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
)
930 if (package
->platform
== PLATFORM_INTEL
)
931 access
|= KEY_WOW64_32KEY
;
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
)
945 comp
= cls
->Component
;
951 TRACE("component is disabled\n");
955 feature
= cls
->Feature
;
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
));
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
);
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
) );
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
)
1014 return progid
->Class
->clsid
;
1015 if (progid
->Parent
== progid
)
1017 progid
= progid
->Parent
;
1022 static UINT
register_progid( const MSIPROGID
* progid
)
1024 static const WCHAR szCurVer
[] = {'C','u','r','V','e','r',0};
1028 rc
= RegCreateKeyW( HKEY_CLASSES_ROOT
, progid
->ProgID
, &hkey
);
1029 if (rc
== ERROR_SUCCESS
)
1031 LPCWSTR clsid
= get_clsid_of_progid( progid
);
1034 msi_reg_set_subkey_val( hkey
, szCLSID
, NULL
, clsid
);
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 */
1046 msi_reg_set_subkey_val( hkey
, szCurVer
, NULL
, progid
->CurVer
->ProgID
);
1051 ERR("failed to create key %s\n", debugstr_w( progid
->ProgID
) );
1056 static const MSICLASS
*get_progid_class( const MSIPROGID
*progid
)
1060 if (progid
->Parent
) progid
= progid
->Parent
;
1061 if (progid
->Class
) return progid
->Class
;
1062 if (!progid
->Parent
|| progid
->Parent
== progid
) break;
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
;
1085 UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
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
)
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
));
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
;
1134 static BOOL
has_all_extensions_removed( const MSIPACKAGE
*package
, const MSIPROGID
*progid
)
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
;
1147 UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
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
)
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
));
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
)
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};
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
);
1203 size
+= lstrlenW(verb
->Argument
);
1206 command
= msi_alloc(size
* sizeof (WCHAR
));
1208 swprintf(command
, size
, fmt
, component
->FullKeypath
, verb
->Argument
);
1210 swprintf(command
, size
, fmt2
, component
->FullKeypath
);
1212 msi_reg_set_val_str( key
, NULL
, command
);
1215 advertise
= msi_create_component_advertise_string(package
, component
,
1216 extension
->Feature
->Feature
);
1217 size
= lstrlenW(advertise
);
1220 size
+= lstrlenW(verb
->Argument
);
1223 command
= msi_alloc_zero(size
* sizeof (WCHAR
));
1225 lstrcpyW(command
,advertise
);
1228 lstrcatW(command
,szSpace
);
1229 lstrcatW(command
,verb
->Argument
);
1232 msi_reg_set_val_multi_str( key
, szCommand
, command
);
1236 msi_free(advertise
);
1241 keyname
= msi_build_directory_name( 3, progid
, szShell
, verb
->Verb
);
1242 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, keyname
, NULL
, verb
->Command
);
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
);
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};
1265 BOOL install_on_demand
= TRUE
;
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
)
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
)
1284 MSIFEATURE
*feature
;
1286 if (!ext
->Component
)
1289 if (!ext
->Component
->Enabled
)
1291 TRACE("component is disabled\n");
1295 feature
= ext
->Feature
;
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
));
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
) );
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
);
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};
1337 INT Sequence
= MSI_NULL_INTEGER
;
1340 progid
= ext
->ProgID
->ProgID
;
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
);
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
);
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
)
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
)
1387 LIST_FOR_EACH_ENTRY( ext
, &package
->extensions
, MSIEXTENSION
, entry
)
1390 MSIFEATURE
*feature
;
1392 if (!ext
->Component
)
1395 if (!ext
->Component
->Enabled
)
1397 TRACE("component is disabled\n");
1401 feature
= ext
->Feature
;
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
));
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
) );
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};
1431 LPWSTR progid_shell
;
1434 progid
= ext
->ProgID
->ProgID
;
1436 progid
= ext
->ProgIDText
;
1438 progid_shell
= msi_alloc( (lstrlenW( progid
) + lstrlenW( shellW
) + 1) * sizeof(WCHAR
) );
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};
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
)
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
));
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
)
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
);
1503 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, key
, szCLSID
, mt
->clsid
);
1505 msi_free( extension
);
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
)
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
)
1530 LIST_FOR_EACH_ENTRY( mime
, &package
->mimes
, MSIMIME
, entry
)
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
));
1542 TRACE("Unregistering MIME type %s\n", debugstr_w(mime
->ContentType
));
1544 mime_key
= msi_alloc( (lstrlenW( szMIMEDatabase
) + lstrlenW( mime
->ContentType
) + 1) * sizeof(WCHAR
) );
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
;