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
35 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
37 static MSIAPPID
*load_appid( MSIPACKAGE
* package
, MSIRECORD
*row
)
42 /* fill in the data */
44 appid
= msi_alloc_zero( sizeof(MSIAPPID
) );
48 appid
->AppID
= msi_dup_record_field( row
, 1 );
49 TRACE("loading appid %s\n", debugstr_w( appid
->AppID
));
51 buffer
= MSI_RecordGetString(row
,2);
52 deformat_string( package
, buffer
, &appid
->RemoteServerName
);
54 appid
->LocalServer
= msi_dup_record_field(row
,3);
55 appid
->ServiceParameters
= msi_dup_record_field(row
,4);
56 appid
->DllSurrogate
= msi_dup_record_field(row
,5);
58 appid
->ActivateAtStorage
= !MSI_RecordIsNull(row
,6);
59 appid
->RunAsInteractiveUser
= !MSI_RecordIsNull(row
,7);
61 list_add_tail( &package
->appids
, &appid
->entry
);
66 static MSIAPPID
*load_given_appid( MSIPACKAGE
*package
, LPCWSTR name
)
68 static const WCHAR query
[] = {
69 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
70 '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
71 '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
78 /* check for appids already loaded */
79 LIST_FOR_EACH_ENTRY( appid
, &package
->appids
, MSIAPPID
, entry
)
81 if (!strcmpiW( appid
->AppID
, name
))
83 TRACE("found appid %s %p\n", debugstr_w(name
), appid
);
88 row
= MSI_QueryGetRecord(package
->db
, query
, name
);
92 appid
= load_appid(package
, row
);
93 msiobj_release(&row
->hdr
);
97 static MSIPROGID
*load_given_progid(MSIPACKAGE
*package
, LPCWSTR progid
);
98 static MSICLASS
*load_given_class( MSIPACKAGE
*package
, LPCWSTR classid
);
100 static MSIPROGID
*load_progid( MSIPACKAGE
* package
, MSIRECORD
*row
)
105 /* fill in the data */
107 progid
= msi_alloc_zero( sizeof(MSIPROGID
) );
111 list_add_tail( &package
->progids
, &progid
->entry
);
113 progid
->ProgID
= msi_dup_record_field(row
,1);
114 TRACE("loading progid %s\n",debugstr_w(progid
->ProgID
));
116 buffer
= MSI_RecordGetString(row
,2);
117 progid
->Parent
= load_given_progid(package
,buffer
);
118 if (progid
->Parent
== NULL
&& buffer
)
119 FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer
));
121 buffer
= MSI_RecordGetString(row
,3);
122 progid
->Class
= load_given_class(package
,buffer
);
123 if (progid
->Class
== NULL
&& buffer
)
124 FIXME("Unknown class %s\n",debugstr_w(buffer
));
126 progid
->Description
= msi_dup_record_field(row
,4);
128 if (!MSI_RecordIsNull(row
,6))
130 INT icon_index
= MSI_RecordGetInteger(row
,6);
131 LPCWSTR FileName
= MSI_RecordGetString(row
,5);
133 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
135 FilePath
= msi_build_icon_path(package
, FileName
);
137 progid
->IconPath
= msi_alloc( (strlenW(FilePath
)+10)* sizeof(WCHAR
) );
139 sprintfW(progid
->IconPath
,fmt
,FilePath
,icon_index
);
145 buffer
= MSI_RecordGetString(row
,5);
147 progid
->IconPath
= msi_build_icon_path(package
, buffer
);
150 progid
->CurVer
= NULL
;
151 progid
->VersionInd
= NULL
;
153 /* if we have a parent then we may be that parents CurVer */
154 if (progid
->Parent
&& progid
->Parent
!= progid
)
156 MSIPROGID
*parent
= progid
->Parent
;
158 while (parent
->Parent
&& parent
->Parent
!= parent
)
159 parent
= parent
->Parent
;
161 /* FIXME: need to determine if we are really the CurVer */
163 progid
->CurVer
= parent
;
164 parent
->VersionInd
= progid
;
170 static MSIPROGID
*load_given_progid(MSIPACKAGE
*package
, LPCWSTR name
)
172 static const WCHAR query
[] = {
173 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
174 '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
175 '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
182 /* check for progids already loaded */
183 LIST_FOR_EACH_ENTRY( progid
, &package
->progids
, MSIPROGID
, entry
)
185 if (!strcmpiW( progid
->ProgID
, name
))
187 TRACE("found progid %s (%p)\n",debugstr_w(name
), progid
);
192 row
= MSI_QueryGetRecord( package
->db
, query
, name
);
196 progid
= load_progid(package
, row
);
197 msiobj_release(&row
->hdr
);
201 static MSICLASS
*load_class( MSIPACKAGE
* package
, MSIRECORD
*row
)
207 /* fill in the data */
209 cls
= msi_alloc_zero( sizeof(MSICLASS
) );
213 list_add_tail( &package
->classes
, &cls
->entry
);
215 cls
->clsid
= msi_dup_record_field( row
, 1 );
216 TRACE("loading class %s\n",debugstr_w(cls
->clsid
));
217 cls
->Context
= msi_dup_record_field( row
, 2 );
218 buffer
= MSI_RecordGetString(row
,3);
219 cls
->Component
= msi_get_loaded_component( package
, buffer
);
221 cls
->ProgIDText
= msi_dup_record_field(row
,4);
222 cls
->ProgID
= load_given_progid(package
, cls
->ProgIDText
);
224 cls
->Description
= msi_dup_record_field(row
,5);
226 buffer
= MSI_RecordGetString(row
,6);
228 cls
->AppID
= load_given_appid(package
, buffer
);
230 cls
->FileTypeMask
= msi_dup_record_field(row
,7);
232 if (!MSI_RecordIsNull(row
,9))
235 INT icon_index
= MSI_RecordGetInteger(row
,9);
236 LPCWSTR FileName
= MSI_RecordGetString(row
,8);
238 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
240 FilePath
= msi_build_icon_path(package
, FileName
);
242 cls
->IconPath
= msi_alloc( (strlenW(FilePath
)+5)* sizeof(WCHAR
) );
244 sprintfW(cls
->IconPath
,fmt
,FilePath
,icon_index
);
250 buffer
= MSI_RecordGetString(row
,8);
252 cls
->IconPath
= msi_build_icon_path(package
, buffer
);
255 if (!MSI_RecordIsNull(row
,10))
257 i
= MSI_RecordGetInteger(row
,10);
258 if (i
!= MSI_NULL_INTEGER
&& i
> 0 && i
< 4)
260 static const WCHAR ole2
[] = {'o','l','e','2','.','d','l','l',0};
261 static const WCHAR ole32
[] = {'o','l','e','3','2','.','d','l','l',0};
266 cls
->DefInprocHandler
= strdupW(ole2
);
269 cls
->DefInprocHandler32
= strdupW(ole32
);
272 cls
->DefInprocHandler
= strdupW(ole2
);
273 cls
->DefInprocHandler32
= strdupW(ole32
);
279 cls
->DefInprocHandler32
= msi_dup_record_field( row
, 10 );
280 msi_reduce_to_long_filename( cls
->DefInprocHandler32
);
283 buffer
= MSI_RecordGetString(row
,11);
284 deformat_string(package
,buffer
,&cls
->Argument
);
286 buffer
= MSI_RecordGetString(row
,12);
287 cls
->Feature
= msi_get_loaded_feature(package
, buffer
);
289 cls
->Attributes
= MSI_RecordGetInteger(row
,13);
290 cls
->action
= INSTALLSTATE_UNKNOWN
;
295 * the Class table has 3 primary keys. Generally it is only
296 * referenced through the first CLSID key. However when loading
297 * all of the classes we need to make sure we do not ignore rows
298 * with other Context and ComponentIndexs
300 static MSICLASS
*load_given_class(MSIPACKAGE
*package
, LPCWSTR classid
)
302 static const WCHAR query
[] = {
303 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
304 '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
305 '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
312 /* check for classes already loaded */
313 LIST_FOR_EACH_ENTRY( cls
, &package
->classes
, MSICLASS
, entry
)
315 if (!strcmpiW( cls
->clsid
, classid
))
317 TRACE("found class %s (%p)\n",debugstr_w(classid
), cls
);
322 row
= MSI_QueryGetRecord(package
->db
, query
, classid
);
326 cls
= load_class(package
, row
);
327 msiobj_release(&row
->hdr
);
331 static MSIEXTENSION
*load_given_extension( MSIPACKAGE
*package
, LPCWSTR extension
);
333 static MSIMIME
*load_mime( MSIPACKAGE
* package
, MSIRECORD
*row
)
338 /* fill in the data */
340 mt
= msi_alloc_zero( sizeof(MSIMIME
) );
344 mt
->ContentType
= msi_dup_record_field( row
, 1 );
345 TRACE("loading mime %s\n", debugstr_w(mt
->ContentType
));
347 extension
= MSI_RecordGetString( row
, 2 );
348 mt
->Extension
= load_given_extension( package
, extension
);
349 mt
->suffix
= strdupW( extension
);
351 mt
->clsid
= msi_dup_record_field( row
, 3 );
352 mt
->Class
= load_given_class( package
, mt
->clsid
);
354 list_add_tail( &package
->mimes
, &mt
->entry
);
359 static MSIMIME
*load_given_mime( MSIPACKAGE
*package
, LPCWSTR mime
)
361 static const WCHAR query
[] = {
362 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
363 '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
364 '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ','\'','%','s','\'',0};
371 /* check for mime already loaded */
372 LIST_FOR_EACH_ENTRY( mt
, &package
->mimes
, MSIMIME
, entry
)
374 if (!strcmpiW( mt
->ContentType
, mime
))
376 TRACE("found mime %s (%p)\n",debugstr_w(mime
), mt
);
381 row
= MSI_QueryGetRecord(package
->db
, query
, mime
);
385 mt
= load_mime(package
, row
);
386 msiobj_release(&row
->hdr
);
390 static MSIEXTENSION
*load_extension( MSIPACKAGE
* package
, MSIRECORD
*row
)
395 /* fill in the data */
397 ext
= msi_alloc_zero( sizeof(MSIEXTENSION
) );
401 list_init( &ext
->verbs
);
403 list_add_tail( &package
->extensions
, &ext
->entry
);
405 ext
->Extension
= msi_dup_record_field( row
, 1 );
406 TRACE("loading extension %s\n", debugstr_w(ext
->Extension
));
408 buffer
= MSI_RecordGetString( row
, 2 );
409 ext
->Component
= msi_get_loaded_component( package
, buffer
);
411 ext
->ProgIDText
= msi_dup_record_field( row
, 3 );
412 ext
->ProgID
= load_given_progid( package
, ext
->ProgIDText
);
414 buffer
= MSI_RecordGetString( row
, 4 );
415 ext
->Mime
= load_given_mime( package
, buffer
);
417 buffer
= MSI_RecordGetString(row
,5);
418 ext
->Feature
= msi_get_loaded_feature( package
, buffer
);
419 ext
->action
= INSTALLSTATE_UNKNOWN
;
424 * While the extension table has 2 primary keys, this function is only looking
425 * at the Extension key which is what is referenced as a foreign key
427 static MSIEXTENSION
*load_given_extension( MSIPACKAGE
*package
, LPCWSTR name
)
429 static const WCHAR query
[] = {
430 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
431 '`','E','x','t','e','n','s','i','o','n','`',' ','W','H','E','R','E',' ',
432 '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
442 /* check for extensions already loaded */
443 LIST_FOR_EACH_ENTRY( ext
, &package
->extensions
, MSIEXTENSION
, entry
)
445 if (!strcmpiW( ext
->Extension
, name
))
447 TRACE("extension %s already loaded %p\n", debugstr_w(name
), ext
);
452 row
= MSI_QueryGetRecord( package
->db
, query
, name
);
456 ext
= load_extension(package
, row
);
457 msiobj_release(&row
->hdr
);
461 static UINT
iterate_load_verb(MSIRECORD
*row
, LPVOID param
)
463 MSIPACKAGE
* package
= param
;
466 MSIEXTENSION
*extension
;
468 buffer
= MSI_RecordGetString(row
,1);
469 extension
= load_given_extension( package
, buffer
);
472 ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer
));
473 return ERROR_SUCCESS
;
476 /* fill in the data */
478 verb
= msi_alloc_zero( sizeof(MSIVERB
) );
480 return ERROR_OUTOFMEMORY
;
482 verb
->Verb
= msi_dup_record_field(row
,2);
483 TRACE("loading verb %s\n",debugstr_w(verb
->Verb
));
484 verb
->Sequence
= MSI_RecordGetInteger(row
,3);
486 buffer
= MSI_RecordGetString(row
,4);
487 deformat_string(package
,buffer
,&verb
->Command
);
489 buffer
= MSI_RecordGetString(row
,5);
490 deformat_string(package
,buffer
,&verb
->Argument
);
492 /* associate the verb with the correct extension */
493 list_add_tail( &extension
->verbs
, &verb
->entry
);
495 return ERROR_SUCCESS
;
498 static UINT
iterate_all_classes(MSIRECORD
*rec
, LPVOID param
)
504 MSIPACKAGE
* package
= param
;
508 clsid
= MSI_RecordGetString(rec
,1);
509 context
= MSI_RecordGetString(rec
,2);
510 buffer
= MSI_RecordGetString(rec
,3);
511 comp
= msi_get_loaded_component(package
, buffer
);
513 LIST_FOR_EACH_ENTRY( cls
, &package
->classes
, MSICLASS
, entry
)
515 if (strcmpiW( clsid
, cls
->clsid
))
517 if (strcmpW( context
, cls
->Context
))
519 if (comp
== cls
->Component
)
527 load_class(package
, rec
);
529 return ERROR_SUCCESS
;
532 static UINT
load_all_classes( MSIPACKAGE
*package
)
534 static const WCHAR query
[] = {
535 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','C','l','a','s','s','`',0};
539 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
540 if (rc
!= ERROR_SUCCESS
)
541 return ERROR_SUCCESS
;
543 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_classes
, package
);
544 msiobj_release(&view
->hdr
);
548 static UINT
iterate_all_extensions(MSIRECORD
*rec
, LPVOID param
)
553 MSIPACKAGE
* package
= param
;
557 extension
= MSI_RecordGetString(rec
,1);
558 buffer
= MSI_RecordGetString(rec
,2);
559 comp
= msi_get_loaded_component(package
, buffer
);
561 LIST_FOR_EACH_ENTRY( ext
, &package
->extensions
, MSIEXTENSION
, entry
)
563 if (strcmpiW(extension
, ext
->Extension
))
565 if (comp
== ext
->Component
)
573 load_extension(package
, rec
);
575 return ERROR_SUCCESS
;
578 static UINT
load_all_extensions( MSIPACKAGE
*package
)
580 static const WCHAR query
[] = {
581 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','E','x','t','e','n','s','i','o','n','`',0};
585 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
586 if (rc
!= ERROR_SUCCESS
)
587 return ERROR_SUCCESS
;
589 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_extensions
, package
);
590 msiobj_release(&view
->hdr
);
594 static UINT
iterate_all_progids(MSIRECORD
*rec
, LPVOID param
)
597 MSIPACKAGE
* package
= param
;
599 buffer
= MSI_RecordGetString(rec
,1);
600 load_given_progid(package
,buffer
);
601 return ERROR_SUCCESS
;
604 static UINT
load_all_progids( MSIPACKAGE
*package
)
606 static const WCHAR query
[] = {
607 'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ','F','R','O','M',' ',
608 '`','P','r','o','g','I','d','`',0};
612 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
613 if (rc
!= ERROR_SUCCESS
)
614 return ERROR_SUCCESS
;
616 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_progids
, package
);
617 msiobj_release(&view
->hdr
);
621 static UINT
load_all_verbs( MSIPACKAGE
*package
)
623 static const WCHAR query
[] = {
624 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','V','e','r','b','`',0};
628 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
629 if (rc
!= ERROR_SUCCESS
)
630 return ERROR_SUCCESS
;
632 rc
= MSI_IterateRecords(view
, NULL
, iterate_load_verb
, package
);
633 msiobj_release(&view
->hdr
);
637 static UINT
iterate_all_mimes(MSIRECORD
*rec
, LPVOID param
)
640 MSIPACKAGE
* package
= param
;
642 buffer
= MSI_RecordGetString(rec
,1);
643 load_given_mime(package
,buffer
);
644 return ERROR_SUCCESS
;
647 static UINT
load_all_mimes( MSIPACKAGE
*package
)
649 static const WCHAR query
[] = {
650 'S','E','L','E','C','T',' ','`','C','o','n','t','e','n','t','T','y','p','e','`',' ',
651 'F','R','O','M',' ','`','M','I','M','E','`',0};
655 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
656 if (rc
!= ERROR_SUCCESS
)
657 return ERROR_SUCCESS
;
659 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_mimes
, package
);
660 msiobj_release(&view
->hdr
);
664 static UINT
load_classes_and_such( MSIPACKAGE
*package
)
668 TRACE("Loading all the class info and related tables\n");
670 /* check if already loaded */
671 if (!list_empty( &package
->classes
) ||
672 !list_empty( &package
->mimes
) ||
673 !list_empty( &package
->extensions
) ||
674 !list_empty( &package
->progids
)) return ERROR_SUCCESS
;
676 r
= load_all_classes( package
);
677 if (r
!= ERROR_SUCCESS
) return r
;
679 r
= load_all_extensions( package
);
680 if (r
!= ERROR_SUCCESS
) return r
;
682 r
= load_all_progids( package
);
683 if (r
!= ERROR_SUCCESS
) return r
;
685 /* these loads must come after the other loads */
686 r
= load_all_verbs( package
);
687 if (r
!= ERROR_SUCCESS
) return r
;
689 return load_all_mimes( package
);
692 static UINT
register_appid(const MSIAPPID
*appid
, LPCWSTR app
)
694 static const WCHAR szRemoteServerName
[] =
695 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
696 static const WCHAR szLocalService
[] =
697 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
698 static const WCHAR szService
[] =
699 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
700 static const WCHAR szDLL
[] =
701 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
702 static const WCHAR szActivate
[] =
703 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
704 static const WCHAR szY
[] = {'Y',0};
705 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
706 static const WCHAR szUser
[] =
707 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
711 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
712 RegCreateKeyW( hkey2
, appid
->AppID
, &hkey3
);
714 msi_reg_set_val_str( hkey3
, NULL
, app
);
716 if (appid
->RemoteServerName
)
717 msi_reg_set_val_str( hkey3
, szRemoteServerName
, appid
->RemoteServerName
);
719 if (appid
->LocalServer
)
720 msi_reg_set_val_str( hkey3
, szLocalService
, appid
->LocalServer
);
722 if (appid
->ServiceParameters
)
723 msi_reg_set_val_str( hkey3
, szService
, appid
->ServiceParameters
);
725 if (appid
->DllSurrogate
)
726 msi_reg_set_val_str( hkey3
, szDLL
, appid
->DllSurrogate
);
728 if (appid
->ActivateAtStorage
)
729 msi_reg_set_val_str( hkey3
, szActivate
, szY
);
731 if (appid
->RunAsInteractiveUser
)
732 msi_reg_set_val_str( hkey3
, szRunAs
, szUser
);
735 return ERROR_SUCCESS
;
738 UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
)
740 static const WCHAR szFileType_fmt
[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
741 const WCHAR
*keypath
;
743 HKEY hkey
, hkey2
, hkey3
;
747 r
= load_classes_and_such( package
);
748 if (r
!= ERROR_SUCCESS
)
751 if (is_64bit
&& package
->platform
== PLATFORM_INTEL
)
752 keypath
= szWow6432NodeCLSID
;
756 if (RegCreateKeyW(HKEY_CLASSES_ROOT
, keypath
, &hkey
) != ERROR_SUCCESS
)
757 return ERROR_FUNCTION_FAILED
;
759 LIST_FOR_EACH_ENTRY( cls
, &package
->classes
, MSICLASS
, entry
)
767 comp
= cls
->Component
;
773 TRACE("component is disabled\n");
777 feature
= cls
->Feature
;
781 feature
->Action
= msi_get_feature_action( package
, feature
);
782 if (feature
->Action
!= INSTALLSTATE_LOCAL
&&
783 feature
->Action
!= INSTALLSTATE_ADVERTISED
)
785 TRACE("feature %s not scheduled for installation, skipping registration of class %s\n",
786 debugstr_w(feature
->Feature
), debugstr_w(cls
->clsid
));
790 if (!comp
->KeyPath
|| !(file
= msi_get_loaded_file( package
, comp
->KeyPath
)))
792 TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls
->clsid
));
795 TRACE("Registering class %s (%p)\n", debugstr_w(cls
->clsid
), cls
);
797 cls
->action
= INSTALLSTATE_LOCAL
;
799 RegCreateKeyW( hkey
, cls
->clsid
, &hkey2
);
801 if (cls
->Description
)
802 msi_reg_set_val_str( hkey2
, NULL
, cls
->Description
);
804 RegCreateKeyW( hkey2
, cls
->Context
, &hkey3
);
807 * FIXME: Implement install on demand (advertised components).
809 * ole32.dll should call msi.MsiProvideComponentFromDescriptor()
810 * when it needs an InProcServer that doesn't exist.
811 * The component advertise string should be in the "InProcServer" value.
813 size
= lstrlenW( file
->TargetPath
)+1;
815 size
+= lstrlenW(cls
->Argument
)+1;
817 argument
= msi_alloc( size
* sizeof(WCHAR
) );
818 lstrcpyW( argument
, file
->TargetPath
);
822 lstrcatW( argument
, szSpace
);
823 lstrcatW( argument
, cls
->Argument
);
826 msi_reg_set_val_str( hkey3
, NULL
, argument
);
831 if (cls
->ProgID
|| cls
->ProgIDText
)
836 progid
= cls
->ProgID
->ProgID
;
838 progid
= cls
->ProgIDText
;
840 msi_reg_set_subkey_val( hkey2
, szProgID
, NULL
, progid
);
842 if (cls
->ProgID
&& cls
->ProgID
->VersionInd
)
844 msi_reg_set_subkey_val( hkey2
, szVIProgID
, NULL
,
845 cls
->ProgID
->VersionInd
->ProgID
);
851 MSIAPPID
*appid
= cls
->AppID
;
852 msi_reg_set_val_str( hkey2
, szAppID
, appid
->AppID
);
853 register_appid( appid
, cls
->Description
);
857 msi_reg_set_subkey_val( hkey2
, szDefaultIcon
, NULL
, cls
->IconPath
);
859 if (cls
->DefInprocHandler
)
860 msi_reg_set_subkey_val( hkey2
, szInprocHandler
, NULL
, cls
->DefInprocHandler
);
862 if (cls
->DefInprocHandler32
)
863 msi_reg_set_subkey_val( hkey2
, szInprocHandler32
, NULL
, cls
->DefInprocHandler32
);
867 /* if there is a FileTypeMask, register the FileType */
868 if (cls
->FileTypeMask
)
873 ptr
= cls
->FileTypeMask
;
876 ptr2
= strchrW(ptr
,';');
879 keyname
= msi_alloc( (strlenW(szFileType_fmt
) + strlenW(cls
->clsid
) + 4) * sizeof(WCHAR
));
880 sprintfW( keyname
, szFileType_fmt
, cls
->clsid
, index
);
882 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, keyname
, NULL
, ptr
);
894 uirow
= MSI_CreateRecord(1);
895 MSI_RecordSetStringW( uirow
, 1, cls
->clsid
);
896 msi_ui_actiondata( package
, szRegisterClassInfo
, uirow
);
897 msiobj_release(&uirow
->hdr
);
900 return ERROR_SUCCESS
;
903 UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
905 static const WCHAR szFileType
[] = {'F','i','l','e','T','y','p','e','\\',0};
906 const WCHAR
*keypath
;
912 r
= load_classes_and_such( package
);
913 if (r
!= ERROR_SUCCESS
)
916 if (is_64bit
&& package
->platform
== PLATFORM_INTEL
)
917 keypath
= szWow6432NodeCLSID
;
921 if (RegOpenKeyW( HKEY_CLASSES_ROOT
, keypath
, &hkey
) != ERROR_SUCCESS
)
922 return ERROR_SUCCESS
;
924 LIST_FOR_EACH_ENTRY( cls
, &package
->classes
, MSICLASS
, entry
)
931 comp
= cls
->Component
;
937 TRACE("component is disabled\n");
941 feature
= cls
->Feature
;
945 feature
->Action
= msi_get_feature_action( package
, feature
);
946 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
948 TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n",
949 debugstr_w(feature
->Feature
), debugstr_w(cls
->clsid
));
952 TRACE("Unregistering class %s (%p)\n", debugstr_w(cls
->clsid
), cls
);
954 cls
->action
= INSTALLSTATE_ABSENT
;
956 res
= RegDeleteTreeW( hkey
, cls
->clsid
);
957 if (res
!= ERROR_SUCCESS
)
958 WARN("Failed to delete class key %d\n", res
);
962 res
= RegOpenKeyW( HKEY_CLASSES_ROOT
, szAppID
, &hkey2
);
963 if (res
== ERROR_SUCCESS
)
965 res
= RegDeleteKeyW( hkey2
, cls
->AppID
->AppID
);
966 if (res
!= ERROR_SUCCESS
)
967 WARN("Failed to delete appid key %d\n", res
);
968 RegCloseKey( hkey2
);
971 if (cls
->FileTypeMask
)
973 filetype
= msi_alloc( (strlenW( szFileType
) + strlenW( cls
->clsid
) + 1) * sizeof(WCHAR
) );
976 strcpyW( filetype
, szFileType
);
977 strcatW( filetype
, cls
->clsid
);
978 res
= RegDeleteTreeW( HKEY_CLASSES_ROOT
, filetype
);
979 msi_free( filetype
);
981 if (res
!= ERROR_SUCCESS
)
982 WARN("Failed to delete file type %d\n", res
);
986 uirow
= MSI_CreateRecord( 1 );
987 MSI_RecordSetStringW( uirow
, 1, cls
->clsid
);
988 msi_ui_actiondata( package
, szUnregisterClassInfo
, uirow
);
989 msiobj_release( &uirow
->hdr
);
992 return ERROR_SUCCESS
;
995 static LPCWSTR
get_clsid_of_progid( const MSIPROGID
*progid
)
1000 return progid
->Class
->clsid
;
1001 if (progid
->Parent
== progid
)
1003 progid
= progid
->Parent
;
1008 static UINT
register_progid( const MSIPROGID
* progid
)
1010 static const WCHAR szCurVer
[] = {'C','u','r','V','e','r',0};
1014 rc
= RegCreateKeyW( HKEY_CLASSES_ROOT
, progid
->ProgID
, &hkey
);
1015 if (rc
== ERROR_SUCCESS
)
1017 LPCWSTR clsid
= get_clsid_of_progid( progid
);
1020 msi_reg_set_subkey_val( hkey
, szCLSID
, NULL
, clsid
);
1022 TRACE("%s has no class\n", debugstr_w( progid
->ProgID
) );
1024 if (progid
->Description
)
1025 msi_reg_set_val_str( hkey
, NULL
, progid
->Description
);
1027 if (progid
->IconPath
)
1028 msi_reg_set_subkey_val( hkey
, szDefaultIcon
, NULL
, progid
->IconPath
);
1030 /* write out the current version */
1032 msi_reg_set_subkey_val( hkey
, szCurVer
, NULL
, progid
->CurVer
->ProgID
);
1037 ERR("failed to create key %s\n", debugstr_w( progid
->ProgID
) );
1042 static const MSICLASS
*get_progid_class( const MSIPROGID
*progid
)
1046 if (progid
->Parent
) progid
= progid
->Parent
;
1047 if (progid
->Class
) return progid
->Class
;
1048 if (!progid
->Parent
|| progid
->Parent
== progid
) break;
1053 static BOOL
has_class_installed( const MSIPROGID
*progid
)
1055 const MSICLASS
*class = get_progid_class( progid
);
1056 if (!class || !class->ProgID
) return FALSE
;
1057 return (class->action
== INSTALLSTATE_LOCAL
);
1060 static BOOL
has_one_extension_installed( const MSIPACKAGE
*package
, const MSIPROGID
*progid
)
1062 const MSIEXTENSION
*extension
;
1063 LIST_FOR_EACH_ENTRY( extension
, &package
->extensions
, MSIEXTENSION
, entry
)
1065 if (extension
->ProgID
== progid
&& !list_empty( &extension
->verbs
) &&
1066 extension
->action
== INSTALLSTATE_LOCAL
) return TRUE
;
1071 UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
1077 r
= load_classes_and_such( package
);
1078 if (r
!= ERROR_SUCCESS
)
1081 LIST_FOR_EACH_ENTRY( progid
, &package
->progids
, MSIPROGID
, entry
)
1083 if (!has_class_installed( progid
) && !has_one_extension_installed( package
, progid
))
1085 TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid
->ProgID
));
1088 TRACE("Registering progid %s\n", debugstr_w(progid
->ProgID
));
1090 register_progid( progid
);
1092 uirow
= MSI_CreateRecord( 1 );
1093 MSI_RecordSetStringW( uirow
, 1, progid
->ProgID
);
1094 msi_ui_actiondata( package
, szRegisterProgIdInfo
, uirow
);
1095 msiobj_release( &uirow
->hdr
);
1097 return ERROR_SUCCESS
;
1100 static BOOL
has_class_removed( const MSIPROGID
*progid
)
1102 const MSICLASS
*class = get_progid_class( progid
);
1103 if (!class || !class->ProgID
) return FALSE
;
1104 return (class->action
== INSTALLSTATE_ABSENT
);
1107 static BOOL
has_extensions( const MSIPACKAGE
*package
, const MSIPROGID
*progid
)
1109 const MSIEXTENSION
*extension
;
1110 LIST_FOR_EACH_ENTRY( extension
, &package
->extensions
, MSIEXTENSION
, entry
)
1112 if (extension
->ProgID
== progid
&& !list_empty( &extension
->verbs
)) return TRUE
;
1117 static BOOL
has_all_extensions_removed( const MSIPACKAGE
*package
, const MSIPROGID
*progid
)
1120 const MSIEXTENSION
*extension
;
1121 LIST_FOR_EACH_ENTRY( extension
, &package
->extensions
, MSIEXTENSION
, entry
)
1123 if (extension
->ProgID
== progid
&& !list_empty( &extension
->verbs
) &&
1124 extension
->action
== INSTALLSTATE_ABSENT
) ret
= TRUE
;
1130 UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
1137 r
= load_classes_and_such( package
);
1138 if (r
!= ERROR_SUCCESS
)
1141 LIST_FOR_EACH_ENTRY( progid
, &package
->progids
, MSIPROGID
, entry
)
1143 if (!has_class_removed( progid
) ||
1144 (has_extensions( package
, progid
) && !has_all_extensions_removed( package
, progid
)))
1146 TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid
->ProgID
));
1149 TRACE("Unregistering progid %s\n", debugstr_w(progid
->ProgID
));
1151 res
= RegDeleteTreeW( HKEY_CLASSES_ROOT
, progid
->ProgID
);
1152 if (res
!= ERROR_SUCCESS
)
1153 TRACE("Failed to delete progid key %d\n", res
);
1155 uirow
= MSI_CreateRecord( 1 );
1156 MSI_RecordSetStringW( uirow
, 1, progid
->ProgID
);
1157 msi_ui_actiondata( package
, szUnregisterProgIdInfo
, uirow
);
1158 msiobj_release( &uirow
->hdr
);
1160 return ERROR_SUCCESS
;
1163 static UINT
register_verb(MSIPACKAGE
*package
, LPCWSTR progid
,
1164 MSICOMPONENT
* component
, const MSIEXTENSION
* extension
,
1165 MSIVERB
* verb
, INT
* Sequence
)
1169 static const WCHAR szShell
[] = {'s','h','e','l','l',0};
1170 static const WCHAR szCommand
[] = {'c','o','m','m','a','n','d',0};
1171 static const WCHAR fmt
[] = {'\"','%','s','\"',' ','%','s',0};
1172 static const WCHAR fmt2
[] = {'\"','%','s','\"',0};
1177 keyname
= msi_build_directory_name(4, progid
, szShell
, verb
->Verb
, szCommand
);
1179 TRACE("Making Key %s\n",debugstr_w(keyname
));
1180 RegCreateKeyW(HKEY_CLASSES_ROOT
, keyname
, &key
);
1181 size
= strlenW(component
->FullKeypath
);
1183 size
+= strlenW(verb
->Argument
);
1186 command
= msi_alloc(size
* sizeof (WCHAR
));
1188 sprintfW(command
, fmt
, component
->FullKeypath
, verb
->Argument
);
1190 sprintfW(command
, fmt2
, component
->FullKeypath
);
1192 msi_reg_set_val_str( key
, NULL
, command
);
1195 advertise
= msi_create_component_advertise_string(package
, component
,
1196 extension
->Feature
->Feature
);
1197 size
= strlenW(advertise
);
1200 size
+= strlenW(verb
->Argument
);
1203 command
= msi_alloc_zero(size
* sizeof (WCHAR
));
1205 strcpyW(command
,advertise
);
1208 strcatW(command
,szSpace
);
1209 strcatW(command
,verb
->Argument
);
1212 msi_reg_set_val_multi_str( key
, szCommand
, command
);
1216 msi_free(advertise
);
1221 keyname
= msi_build_directory_name( 3, progid
, szShell
, verb
->Verb
);
1222 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, keyname
, NULL
, verb
->Command
);
1226 if (verb
->Sequence
!= MSI_NULL_INTEGER
)
1228 if (*Sequence
== MSI_NULL_INTEGER
|| verb
->Sequence
< *Sequence
)
1230 *Sequence
= verb
->Sequence
;
1231 keyname
= msi_build_directory_name( 2, progid
, szShell
);
1232 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, keyname
, NULL
, verb
->Verb
);
1236 return ERROR_SUCCESS
;
1239 UINT
ACTION_RegisterExtensionInfo(MSIPACKAGE
*package
)
1241 static const WCHAR szContentType
[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0};
1245 BOOL install_on_demand
= TRUE
;
1249 r
= load_classes_and_such( package
);
1250 if (r
!= ERROR_SUCCESS
)
1253 /* We need to set install_on_demand based on if the shell handles advertised
1254 * shortcuts and the like. Because Mike McCormack is working on this i am
1255 * going to default to TRUE
1258 LIST_FOR_EACH_ENTRY( ext
, &package
->extensions
, MSIEXTENSION
, entry
)
1261 MSIFEATURE
*feature
;
1263 if (!ext
->Component
)
1266 if (!ext
->Component
->Enabled
)
1268 TRACE("component is disabled\n");
1272 feature
= ext
->Feature
;
1277 * yes. MSDN says that these are based on _Feature_ not on
1278 * Component. So verify the feature is to be installed
1280 feature
->Action
= msi_get_feature_action( package
, feature
);
1281 if (feature
->Action
!= INSTALLSTATE_LOCAL
&&
1282 !(install_on_demand
&& feature
->Action
== INSTALLSTATE_ADVERTISED
))
1284 TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n",
1285 debugstr_w(feature
->Feature
), debugstr_w(ext
->Extension
));
1288 TRACE("Registering extension %s (%p)\n", debugstr_w(ext
->Extension
), ext
);
1290 ext
->action
= INSTALLSTATE_LOCAL
;
1292 extension
= msi_alloc( (strlenW( ext
->Extension
) + 2) * sizeof(WCHAR
) );
1296 strcpyW( extension
+ 1, ext
->Extension
);
1297 res
= RegCreateKeyW( HKEY_CLASSES_ROOT
, extension
, &hkey
);
1298 msi_free( extension
);
1299 if (res
!= ERROR_SUCCESS
)
1300 WARN("Failed to create extension key %d\n", res
);
1304 msi_reg_set_val_str( hkey
, szContentType
, ext
->Mime
->ContentType
);
1306 if (ext
->ProgID
|| ext
->ProgIDText
)
1308 static const WCHAR szSN
[] =
1309 {'\\','S','h','e','l','l','N','e','w',0};
1314 INT Sequence
= MSI_NULL_INTEGER
;
1317 progid
= ext
->ProgID
->ProgID
;
1319 progid
= ext
->ProgIDText
;
1321 msi_reg_set_val_str( hkey
, NULL
, progid
);
1323 newkey
= msi_alloc( (strlenW(progid
)+strlenW(szSN
)+1) * sizeof(WCHAR
));
1325 strcpyW(newkey
,progid
);
1326 strcatW(newkey
,szSN
);
1327 RegCreateKeyW(hkey
,newkey
,&hkey2
);
1332 /* do all the verbs */
1333 LIST_FOR_EACH_ENTRY( verb
, &ext
->verbs
, MSIVERB
, entry
)
1335 register_verb( package
, progid
, ext
->Component
,
1336 ext
, verb
, &Sequence
);
1342 uirow
= MSI_CreateRecord(1);
1343 MSI_RecordSetStringW( uirow
, 1, ext
->Extension
);
1344 msi_ui_actiondata( package
, szRegisterExtensionInfo
, uirow
);
1345 msiobj_release(&uirow
->hdr
);
1347 return ERROR_SUCCESS
;
1350 UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
1357 r
= load_classes_and_such( package
);
1358 if (r
!= ERROR_SUCCESS
)
1361 LIST_FOR_EACH_ENTRY( ext
, &package
->extensions
, MSIEXTENSION
, entry
)
1364 MSIFEATURE
*feature
;
1366 if (!ext
->Component
)
1369 if (!ext
->Component
->Enabled
)
1371 TRACE("component is disabled\n");
1375 feature
= ext
->Feature
;
1379 feature
->Action
= msi_get_feature_action( package
, feature
);
1380 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
1382 TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n",
1383 debugstr_w(feature
->Feature
), debugstr_w(ext
->Extension
));
1386 TRACE("Unregistering extension %s\n", debugstr_w(ext
->Extension
));
1388 ext
->action
= INSTALLSTATE_ABSENT
;
1390 extension
= msi_alloc( (strlenW( ext
->Extension
) + 2) * sizeof(WCHAR
) );
1394 strcpyW( extension
+ 1, ext
->Extension
);
1395 res
= RegDeleteTreeW( HKEY_CLASSES_ROOT
, extension
);
1396 msi_free( extension
);
1397 if (res
!= ERROR_SUCCESS
)
1398 WARN("Failed to delete extension key %d\n", res
);
1401 if (ext
->ProgID
|| ext
->ProgIDText
)
1403 static const WCHAR shellW
[] = {'\\','s','h','e','l','l',0};
1405 LPWSTR progid_shell
;
1408 progid
= ext
->ProgID
->ProgID
;
1410 progid
= ext
->ProgIDText
;
1412 progid_shell
= msi_alloc( (strlenW( progid
) + strlenW( shellW
) + 1) * sizeof(WCHAR
) );
1415 strcpyW( progid_shell
, progid
);
1416 strcatW( progid_shell
, shellW
);
1417 res
= RegDeleteTreeW( HKEY_CLASSES_ROOT
, progid_shell
);
1418 msi_free( progid_shell
);
1419 if (res
!= ERROR_SUCCESS
)
1420 WARN("Failed to delete shell key %d\n", res
);
1421 RegDeleteKeyW( HKEY_CLASSES_ROOT
, progid
);
1425 uirow
= MSI_CreateRecord( 1 );
1426 MSI_RecordSetStringW( uirow
, 1, ext
->Extension
);
1427 msi_ui_actiondata( package
, szUnregisterExtensionInfo
, uirow
);
1428 msiobj_release( &uirow
->hdr
);
1430 return ERROR_SUCCESS
;
1433 UINT
ACTION_RegisterMIMEInfo(MSIPACKAGE
*package
)
1435 static const WCHAR szExtension
[] = {'E','x','t','e','n','s','i','o','n',0};
1440 r
= load_classes_and_such( package
);
1441 if (r
!= ERROR_SUCCESS
)
1444 LIST_FOR_EACH_ENTRY( mt
, &package
->mimes
, MSIMIME
, entry
)
1446 LPWSTR extension
, key
;
1449 * check if the MIME is to be installed. Either as requested by an
1450 * extension or Class
1452 if ((!mt
->Class
|| mt
->Class
->action
!= INSTALLSTATE_LOCAL
) &&
1453 mt
->Extension
->action
!= INSTALLSTATE_LOCAL
)
1455 TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt
->ContentType
));
1459 TRACE("Registering MIME type %s\n", debugstr_w(mt
->ContentType
));
1461 extension
= msi_alloc( (strlenW( mt
->Extension
->Extension
) + 2) * sizeof(WCHAR
) );
1462 key
= msi_alloc( (strlenW( mt
->ContentType
) + strlenW( szMIMEDatabase
) + 1) * sizeof(WCHAR
) );
1464 if (extension
&& key
)
1467 strcpyW( extension
+ 1, mt
->Extension
->Extension
);
1469 strcpyW( key
, szMIMEDatabase
);
1470 strcatW( key
, mt
->ContentType
);
1471 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, key
, szExtension
, extension
);
1474 msi_reg_set_subkey_val( HKEY_CLASSES_ROOT
, key
, szCLSID
, mt
->clsid
);
1476 msi_free( extension
);
1479 uirow
= MSI_CreateRecord( 2 );
1480 MSI_RecordSetStringW( uirow
, 1, mt
->ContentType
);
1481 MSI_RecordSetStringW( uirow
, 2, mt
->suffix
);
1482 msi_ui_actiondata( package
, szRegisterMIMEInfo
, uirow
);
1483 msiobj_release( &uirow
->hdr
);
1485 return ERROR_SUCCESS
;
1488 UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
1494 r
= load_classes_and_such( package
);
1495 if (r
!= ERROR_SUCCESS
)
1498 LIST_FOR_EACH_ENTRY( mime
, &package
->mimes
, MSIMIME
, entry
)
1503 if ((!mime
->Class
|| mime
->Class
->action
!= INSTALLSTATE_ABSENT
) &&
1504 mime
->Extension
->action
!= INSTALLSTATE_ABSENT
)
1506 TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime
->ContentType
));
1510 TRACE("Unregistering MIME type %s\n", debugstr_w(mime
->ContentType
));
1512 mime_key
= msi_alloc( (strlenW( szMIMEDatabase
) + strlenW( mime
->ContentType
) + 1) * sizeof(WCHAR
) );
1515 strcpyW( mime_key
, szMIMEDatabase
);
1516 strcatW( mime_key
, mime
->ContentType
);
1517 res
= RegDeleteKeyW( HKEY_CLASSES_ROOT
, mime_key
);
1518 if (res
!= ERROR_SUCCESS
)
1519 WARN("Failed to delete MIME key %d\n", res
);
1520 msi_free( mime_key
);
1523 uirow
= MSI_CreateRecord( 2 );
1524 MSI_RecordSetStringW( uirow
, 1, mime
->ContentType
);
1525 MSI_RecordSetStringW( uirow
, 2, mime
->suffix
);
1526 msi_ui_actiondata( package
, szUnregisterMIMEInfo
, uirow
);
1527 msiobj_release( &uirow
->hdr
);
1529 return ERROR_SUCCESS
;